Description

This R notebook is a bioinformatics pipeline to analyze fitness data obtained from a barcoded transposon library in Ralstonia eutropha a.k.a. Cupriavidus necator. For background and details regarding the method, see Wetmore at al., mBio, 2015 and Price et al., Nature, 2018).

Libraries

# optionally install repos from github
# devtools::install_github("m-jahn/lattice-tools")
# devtools::install_github("m-jahn/R-tools")
library(lattice)
library(latticeExtra)
library(latticetools)
library(tidyverse)
library(dendextend)
library(Rtools)
library(colorspace)

Overview of barcode/transposon read counts

Data import and processing

Read in the main data tables with A) reads per barcode and sample (‘pool counts’), and B) the fitness tables. Tables were obtained by processing sequencing data with a custom BarSeq pipeline. The 32 generation sequencing samples are removed due to the low read count in the continuous samples.

Summary statistics

Overview about the number of reads per barcode, barcodes per gene and so on. Around 8-10 M reads were mapped on average, per sample.

# Number of total mapped reads
df_counts %>% group_by(sample) %>%
  summarize(n_million_reads = sum(n_reads)/10^6) %>%
  barchart(factor(sample) ~ n_million_reads, .,
    par.settings = custom.colorblind(),
    horizontal = TRUE, border = NULL,
    scales = list(y = list(cex = 0.7)),
    panel = function(x, y, ...) {
      panel.grid(h = -1, v = -1, col = grey(0.9))
      panel.barchart(x, y, ...)
    }
  )

Distribution of number of reads per barcode. There is a sufficient number of reads for quantification, on average log2(n) = 5 = 32 reads per barcode.

plot_reads_per_bc <- histogram(~ log2(n_reads) | sample,
  df_counts, as.table = TRUE, layout = c(8,6),
  par.settings = custom.colorblind(),
  between = list(x = 0.5, y = 0.5),
  xlab = expression("log"[2]*" reads per barcode"),
  scales = list(alternating = FALSE),
  panel = function(x, ...) {
    panel.grid(h = -1, v = -1, col = grey(0.9))
    panel.histogram(x, border = "white", ...)
  }
)

print(plot_reads_per_bc)

Similarly to the above, this is an overview about the number of barcodes per gene as a histogram. This distribution is the same for all conditions and replicates. The second plot is the number of reads per gene, averaged as median over all conditions (excluding 0 time point where counts were averaged by BarSeq pipeline). The average reads per gene are log2(n) = 8, which translates to n = 2^8 or around 256 reads per gene.

plot_reads_per_bc <- histogram(~ Strains_per_gene,
  df_fitness %>% select(locus_tag, Strains_per_gene) %>% 
    distinct %>% filter(Strains_per_gene < 40), 
  par.settings = custom.colorblind(), breaks = 20, xlim=c(-2, 42),
  xlab = expression("mutants per gene"),
  panel = function(x, ...) {
    panel.grid(h = -1, v = -1, col = grey(0.9))
    panel.histogram(x, border = "white", ...)
    panel.ablineq(v = mean(x, na.rm = TRUE),
      fontfamily = "FreeSans", col = grey(0.5), lwd = 2, lty = 2)
  }
)

plot_reads_per_gene <- histogram(~ log2(reads_per_gene_median),
  df_fitness %>% filter(Time != 0) %>% group_by(locus_tag) %>%
    summarize(reads_per_gene_median = median(Counts)),
  par.settings = custom.colorblind(), breaks = 20,
  xlab = expression("log"[2]*" reads per gene (med)"),
  panel = function(x, ...) {
    panel.grid(h = -1, v = -1, col = grey(0.9))
    panel.histogram(x, border = "white", ...)
    panel.ablineq(v = mean(x[!is.infinite(x)]),
      fontfamily = "FreeSans", col = grey(0.5), lwd = 2, lty = 2)
  }
)

print(plot_reads_per_bc, split = c(1,1,2,1), more = TRUE)
print(plot_reads_per_gene, split = c(2,1,2,1))

Gene fitness analysis

Depletion over time (generations)

We can plot log2 FC or normalized gene fitness over generations. For this type of overview it is best to summarize individual replicates (4x) to the mean or median, per time point and condition. We also add genome annotation to the summary table. The plots shows that depletion of some strains is so strong already at 8 generations that fitness/log2 FC could not be quantified for 16 generations due to missing read counts. It is best to focus on 8 generations as because it provides a more complete picture.

df_fitness_summary <- df_fitness %>%
  group_by(locus_tag, scaffold, Time, Condition, Substrate, Strains_per_gene) %>%
  summarize(
    Norm_fg_median = median(Norm_fg, na.rm = TRUE),
    log2FC_median = median(log2FC, na.rm = TRUE),
    tstat_median = median(t, na.rm = TRUE)
  ) %>%
  left_join(df_ref)
`summarise()` has grouped output by 'locus_tag', 'scaffold', 'Time', 'Condition', 'Substrate'. You can override using the `.groups` argument.
Joining, by = "locus_tag"
plot_hist_log2FC <- df_fitness_summary %>%
  filter(all(!is.infinite(log2FC_median))) %>%
  group_by(Condition, Substrate) %>%
  slice(1:2000) %>%
  
  xyplot(log2FC_median ~ Time | Substrate * Condition, .,
    groups = locus_tag, as.table = TRUE,
    col = stdcol[1], alpha = 0.2, layout = c(3, 2),
    xlab = "", ylab = expression("log"[2]*" FC"),
    par.settings = custom.colorblind(), type = c("l"),
    between = list(x = 0.5, y = 0.5),
    scales = list(alternating = FALSE), lwd = 2,
    panel = function(x, y, ...) {
      panel.grid(h = -1, v = -1, col = grey(0.9))
      panel.xyplot(x, y, ...)
    }
  )

plot_hist_normfg <- df_fitness_summary %>%
  filter(all(!is.infinite(log2FC_median))) %>%
  group_by(Condition, Substrate) %>%
  slice(1:2000) %>%
  
  xyplot(Norm_fg_median ~ Time | Substrate * Condition, .,
    groups = locus_tag, as.table = TRUE,
    col = stdcol[2], alpha = 0.2, layout = c(3, 2),
    xlab = "generations", ylab = "fitness",
    par.settings = custom.colorblind(), type = c("l"),
    between = list(x = 0.5, y = 0.5),
    scales = list(alternating = FALSE), lwd = 2,
    panel = function(x, y, ...) {
      panel.grid(h = -1, v = -1, col = grey(0.9))
      panel.xyplot(x, y, ...)
    }
  )

print(plot_hist_log2FC, position = c(0,0.47,1,1), more = TRUE)
print(plot_hist_normfg, position = c(0,0,1,0.53))

As sort of an internal control, we compare the gene fitness obtained by a complex procedure to the log2 FC of read counts, which is a very simple measure of ‘fitness’. The two variables correlate well all tested conditions and substrates.

df_fitness_summary %>%
  filter(Time == 8, all(!is.infinite(log2FC_median))) %>%
  
  xyplot(Norm_fg_median ~ log2FC_median |  Substrate * Condition, .,
    as.table = TRUE, col = stdcol[5], pch = 19,
    alpha = 0.4, cex = 0.6,
    layout = c(3, 2), xlim = c(-8,3), ylim = c(-6,5),
    xlab = expression("log"[2]*" FC"), ylab = "fitness",
    par.settings = custom.colorblind(),
    between = list(x = 0.5, y = 0.5),
    scales = list(alternating = FALSE),
    panel = function(x, y, ...) {
      panel.grid(h = -1, v = -1, col = grey(0.9))
      panel.xyplot(x, y, ...)
      panel.lmlineq(x, y, fontfamily = "FreeSans", r.squared = TRUE, lwd = 1.5, 
        col.text = 1, pos = 3, offset = 5, ...)
      panel.abline(a = 2, b = 1, col = grey(0.5), lty = 2, lwd = 1.5)
    }
  )

Comparing gene fitness between conditions

Similarly to Figure 2 in Wetmore et al, mBIO, 2015, we can investigate condition-dependent gene fitness by comparing conditions and substrates one-on-one. The correlation between substrates and growth regimes (continuous, pulsed) is quite different. The strongest correlation does exist for the pulsed vs continuous regime for each substrate (R = 0.64 to 0.87). And for the pulsed conditions, comparison between substrates (R = 0.62 to 0.72).

df_fitness_comp <- df_fitness_summary %>% filter(Time == 8) %>%
  group_by(locus_tag) %>% mutate(tstat_median = min(tstat_median)) %>%
  select(locus_tag, Condition, Substrate, Norm_fg_median, gene_name, COG_Process, tstat_median) %>%
  unite(Condition, Condition, Substrate) %>%
  pivot_wider(names_from = Condition, values_from = Norm_fg_median) %>%
  filter(!is.na(locus_tag))

custom_splom(df_fitness_comp %>% ungroup %>% 
  select(matches("conti|pulse")), col = grey(0.4, 0.4))

We can also compare selected conditions directly to identify genes enriched or depleted in several conditions.

# generalized plotting function
plot_fitness_comp <- function(data, vars){
  xyplot(get(vars[2]) ~ get(vars[1]), data,
    groups = abs(get(vars[1])-get(vars[2])) > 2, #tstat_median < -3
    par.settings = custom.colorblind(), col = stdcol[c(5,1)],
    pch = 19, alpha = 0.5, cex = 0.7, aspect = 1,
    xlim = c(-7, 4), ylim = c(-7, 4),
    xlab = vars[1], ylab = vars[2],
    panel = function(x, y, ...) {
      panel.grid(h = -1, v = -1, col = grey(0.9))
      panel.abline(v = 0, h = 0, col = grey(0.5), lty = 2, lwd = 1.5)
      panel.abline(a = 0, b = 1, col = grey(0.5), lty = 2, lwd = 1.5)
      panel.abline(a = 2, b = 1, col = grey(0.5), lty = 2, lwd = 1.5)
      panel.abline(a = -2, b = 1, col = grey(0.5), lty = 2, lwd = 1.5)
      panel.xyplot(x, y, ...)
      panel.key(...)
    }
  )
}

plot_fitness_comp(df_fitness_comp, c("continuous_formate", "pulse_formate")) %>%
  print(position = c(0,0.5,0.5,1), more = TRUE)
plot_fitness_comp(df_fitness_comp, c("continuous_fructose", "pulse_fructose")) %>%
  print(position = c(0.5,0.5,1,1), more = TRUE)
plot_fitness_comp(df_fitness_comp, c("continuous_succinate", "pulse_succinate")) %>%
  print(position = c(0,0,0.5,0.5), more = TRUE)
plot_fitness_comp(df_fitness_comp, c("continuous_formate", "continuous_fructose")) %>%
  print(position = c(0.5,0,1,0.5), more = TRUE)

Differential fitness of selected genes

Most genes correlate in fitness value between conditions. That means, only some genes have a condition-specific fitness effect, i.e. increase or decrease fitness of the respective strain in one substrate or growth regime specifically. This section investigates specific genes and their functions that show such differential fitness between conditions. A simple comparison of one condition versus another will not be helpful as there two many possible combinations. To identify interesting sets of genes, cluster analysis can be performed.

# generate colorpalette for heatmap
heat_cols <- colorspace::diverging_hcl(n = 7, h = c(260, 0), c = 100, l = c(50, 90))

# create a matrix from wide fitness data for plotting heatmap
mat_heatmap <- df_fitness_comp %>% ungroup %>%
  filter(if_any(.cols = matches("conti|pulse"), ~ !between(., -2, 2))) %>%
  select(matches("locus_tag|conti|pulse")) %>%
  # filter out NA rows, and replace extreme values
  drop_na %>% mutate(across(matches("conti|pulse"), 
    function(x) {y = replace(x, x > 6, 6); replace(y, y < -6, -6)})) %>%
  column_to_rownames(var = "locus_tag") %>%
  as.matrix

# create cluster for reordering
mat_cluster <- mat_heatmap %>% dist %>% hclust(method = "ward.D")
mat_heatmap <- mat_heatmap[order.dendrogram(as.dendrogram(mat_cluster)), c(1,4,2,5,3,6)]

# plot heatmap
plot_heatmap <- levelplot(mat_heatmap,
  par.settings = custom.colorblind(),
  col.regions = colorRampPalette(heat_cols)(16),
  at = seq(-6, 6, 1), aspect = "fill",
  xlab = "", ylab = "", scales = list(x = list(draw = FALSE)),
  panel = function(x, y, z, ...) {
    panel.levelplot(x, y, z, ...)
    panel.abline(h = 1:5+0.5, col = "white", lwd = 1.5)
  }
)

print(plot_heatmap)

Clustering and silhouette analysis revealed that we have 4 to 7 clusters with acceptable separation, see the plot below. Of these, several clusters stick out:

  1. mutants specifically depleted in formate conditions = essential for formate
  2. mutants depleted in all conditions = essential in minimal medium
  3. mutants enriched in fructose growth, neutral on other substrates
  4. mutants enriched in continuous regime, mostly neutral in pulsed regime
  5. mutants slightly depleted in continuous succinate - low priority
  6. mutants slightly depleted in continuous fructose - low priority
  7. mutants slightly depleted in various conditions - low priority
silhouetteResult <- Rtools::silhouette_analysis(mat_heatmap, mat_cluster, 2:20)

Call:
hclust(d = ., method = "ward.D")

Cluster method   : ward.D 
Distance         : euclidean 
Number of objects: 310 

Silhouette analysis finished for clusters 2 to 20
silhouetteResult$plot.summary


# plot colored dendrogram
plot(color_branches(
  mat_cluster, k = 7,
  groupLabels = TRUE,
  col = stdcol[1:7]
))


# collect names of enriched/depleted genes
list_enriched <- vegan::cutreeord(mat_cluster, k = 7)
Registered S3 method overwritten by 'vegan':
  method     from      
  rev.hclust dendextend
list_enriched %>% table
.
 1  2  3  4  5  6  7 
34 40 14 27 80 67 48 

Enrichment of mutants over time (increased fitness)

One of the most puzzling results is the appearance of (very) fast growing mutants in some conditions. These mutants quickly enrich over only 16 generations to a volume of up to 20% of all library mutants, they “take over the culture”. This phenomenon was not observed previously in experiments with the Synechocystis sp. PCC6803 CRISPRi repression library (Yao et al., Nature Communications, 2020). The CRISPRi library is based on the same principle of depletion and enrichment of mutants depending on the associated fitness.

Strains enriched on fructose

What is the identity of the enriched genes? Which ones are enriched in several conditions? First we identify the mutants highly and specifically enriched on fructose, predominantly in the continuous growth regime.

df_fitness_summary %>%
  filter(locus_tag %in% names(subset(list_enriched, list_enriched == 3))) %>%
  filter(Time == 16) %>%
  barchart_fitness() %>%
  print(position = c(0,0,0.6,1), more = TRUE)

df_fitness_summary %>%
  filter(locus_tag %in% names(subset(list_enriched, list_enriched == 3))) %>%
  linechart_fitness() %>%
  print(position = c(0.58,0,1,1))

Mechanisms enabling faster growth on fructose

The mechanism for increased growth on fructose seems clearly different from the mechanism for faster growth in all other (mainly continuous) conditions. For the fructose set, several genes are functionally linked suggesting a similar mechanism of action,

  1. Genes H16_B0517 (alcohol dehydrogenase) and H16_B1917 (aldehyde dehydrogenase): According to STRING DB, the genes are co-located i.e. either in direct proximity or in the same operon in alpha-, beta- and gamma-proteobacteria, and even cyanobcateria. BioCyc has 17 possible iso-enzymes in Cupriavidus for the 2-enzyme pathway “ethanol degradation 1”: ethanol –> acetaldehyde –> acetyl-CoA (reverse EtOH fermentation, obtain 1 NADH per reaction) catalyzed by both genes. What could be the mechanism for improved growth/yield on fructose? Chemostats are more yield- than growth selective, this pathway is probably functional and secretes EtOH as a fermentation product; KO of this pathway probably increases yield.

  2. Two genes are involved in nitrate respiration/reduction, PHG269 or narK, and H16_B2087, a NarL-family response regulator. NarK is a nitrate transporter, and NarL senses nitrate and then activates transcription of its targets by binding the DNA. According to this paper on NarL by Ruanto et al., 2020, “the Regulon DB database [11] for transcription regulation in E. coli lists 26 gene regulatory regions where NarL has a direct effect on transcript initiation, and it functions as an activator at 11 of these”. It is not clear what effect the KO of nitrate transport could have on growth or yield, nitrate is not part of the medium.

  3. Genes involved in translation/protein folding/sulphur metabolism:

    • H16_B2521, Alpha-ketoglutarate-dependent taurine dioxygenase; taurine is a sulphur carrier
    • H16_A2861, Glutathione S-transferase; Posttranslational modification, protein turnover, chaperones
    • H16_A1138, Thioredoxin; Posttranslational modification, protein turnover, chaperones
    • H16_A1336, yogA/tdcF, putative translation initiation inhibitor,yjg Ffamily; Translation, ribosomal structure and biogenesis
    • H16_A2553, cO, DNA repair protein RecO; Involved in DNA repair and RecF pathway recombination
  4. Several other gene products are presumably regulatory proteins:

    • 16_A0310, transcriptional regulator, GntR-family; Transcription
    • H16_B2215, HTH lysR-type domain-containing protein; helix turn helix DNA binding motif

Strains enriched on formate

Here, the obvious question with biotechnological importance is to find mutants with higher (specific) tolerance to formate, regardless if it’s pulsed or continuously supplied. We explicitly exclude mutants beneficial for other growth conditions too, which are dealt with in the next section. The clustering results of the previous section could not identify formate-specific mutants enriched after 8 generations. We need to lower the filter threshold to detect genes that have a more subtle enrichment (fitness >= 2 for formate, and <= 1 for all other conditions) after 16 generations.

list_fitness_formate <- df_fitness_summary %>%
  group_by(locus_tag, Substrate, Time) %>%
  mutate(formate_hit = case_when(
    Substrate == "formate" & max(Norm_fg_median) >= 2 ~ TRUE,
    Substrate != "formate" & max(Norm_fg_median) <= 1 ~ TRUE,
    TRUE ~ FALSE)
  ) %>% group_by(locus_tag, Time) %>%
  filter(all(formate_hit), n() == 6) %>% 
  pull(locus_tag) %>% unique

df_fitness_summary %>%
  filter(Time == 16, locus_tag %in% list_fitness_formate) %>%
  barchart_fitness() %>%
  print(position = c(0,0,0.6,1), more = TRUE)

df_fitness_summary %>%
  filter(locus_tag %in% list_fitness_formate) %>%
  linechart_fitness() %>%
  print(position = c(0.58,0,1,1))

Mechanisms enabling faster growth on formate

According to STRING DB there are no obvious relationships between these genes except for the pair PHG388 (pcaI, Oxoadipate CoA transferase alpha subunit) and H16_B1583 (pcaD, 3-Oxoadipate enol-lactone hydrolase). Both genes are part of the catechol degradation pathway that is itself a larger part of benzene degradation. The gene products catalyze two sequential reactions 3-oxoadipate-enol-lactone –> 3-oxoadipate (pcaD) –> 3-oxoadipyl-CoA (pcaI). The next reaction catalyzed by four isoenzymes makes succinyl-CoA which ends up in the Citrate cycle. How the KO of this pathway would improve tolerance to formate is unclear.

Strains enriched on succinate

This is similar to the analysis above for formate, with the exception that many mutants associated with higher fitness in succinate conditions enrich only after 16 generations, and only in the continuous regime. This seems be an artifact of read compression. We therefore use the same thresholds as for formate (fitness >= 2 for succinate, and <= 1 for all other conditions) but after 8 instead of 16 generations.

list_fitness_succinate <- df_fitness_summary %>%
  filter(Time == 8) %>%
  group_by(locus_tag, Substrate) %>%
  mutate(succinate_hit = case_when(
    Substrate == "succinate" & max(Norm_fg_median) >= 2 ~ TRUE,
    Substrate != "succinate" & max(Norm_fg_median) <= 1 ~ TRUE,
    TRUE ~ FALSE)
  ) %>% group_by(locus_tag) %>%
  filter(all(succinate_hit), n() == 6, locus_tag != "H16_A2912") %>% 
  pull(locus_tag) %>% unique

df_fitness_summary %>%
  filter(Time == 16, locus_tag %in% list_fitness_succinate) %>%
  barchart_fitness() %>%
  print(position = c(0,0,0.6,1), more = TRUE)

df_fitness_summary %>%
  filter(locus_tag %in% list_fitness_succinate) %>%
  linechart_fitness() %>%
  print(position = c(0.58,0,1,1))

Mechanisms enabling faster growth on succinate

A group of five highly related genes shows significant enrichment in (continuous) succinate: H16_2096 (dppA1), H16_A2406 (dppD2), H16_A2407 (dppC2), H16_A2408 (dppB2), and H16_A2409, dppA2. Alternative names are yejABCDE. All of these proteins are part of an ABC transporter of the PepT family. Quote from PFAM about this type of protein/domain: “All characterised members appear to be involved in the transport of oligopeptides or dipeptides. Some are important for sporulation or antibiotic resistance. Some dipeptide transporters also act on the heme precursor delta-aminolevulinic acid. The enrichment seems to be highly reproducible: each of these genes has 7 to 15 different insertion mutants, all showing the same average pattern. At least two more genes are also involved in (amino acid?) transport, H16_A3284 and H16_A2521. The latter one is a”D-amino acid transferase (D-AAT), required by bacteria to catalyse the synthesis of D-glutamic acid and D-alanine" (PFAM). Supposed mechanism of enrichment: Growth on succinate could lead to a shortage/imbalance of certain amino acids, and investment in uptake might give a growth advantage.

Strains enriched in several conditions

A wealth of genes/mutants are enriched in multiple mainly pulsed growth conditions (cluster 4).

df_fitness_summary %>%
  filter(locus_tag %in% names(subset(list_enriched, list_enriched == 4))) %>%
  filter(Time == 16) %>%
  barchart_fitness() %>%
  print(position = c(0,0,0.6,1), more = TRUE)

df_fitness_summary %>%
  filter(locus_tag %in% names(subset(list_enriched, list_enriched == 4))) %>%
  linechart_fitness() %>%
  print(position = c(0.58,0,1,1))

To learn more about functional relationships between enriched genes/mutants, we can submit the gene list to the STRING interaction database and retrieve a network of probable interactions.

library(ggraph)
library(tidygraph)

# function retrieve network interaction data from STRING DB
# separate gene IDs by "%0d"; species/taxon ID for Cupriavidus necator H16: 381666
# (see https://string-db.org/cgi/organisms)
retrieve_STRING <- function(gene_ID, taxon_ID, min_score = 0000, ref = NULL) {
  gene_list <- paste(gene_ID, collapse = "%0d")
  string_graph <- paste0(
    "https://string-db.org/api/tsv/network?identifiers=", 
    gene_list, "&species=", taxon_ID, "&required_score=", min_score) %>%
  read_tsv(col_types = cols()) %>%
  mutate(across(matches("stringId"), function(x) gsub(paste0(taxon_ID, "."), "", x))) %>%
  as_tbl_graph()
  if (!is.null(ref)) {
    left_join(string_graph, ref, by = "name")
  } else {
    string_graph
  }
}
graph_all_enrich <- retrieve_STRING(
  gene_ID = names(subset(list_enriched, list_enriched == 4)),
  taxon_ID = 381666,
  ref = rename(df_ref, name = locus_tag)
)

graph_all_enrich %>% arrange(COG_Process) %>% activate(edges) %>% 
  filter(score >= 0.4) %>%
  ggraph(layout = 'linear', circular = TRUE) +
  geom_edge_arc(colour = grey(0.6, 0.5), aes(width = score)) + 
  geom_node_point(aes(colour = COG_Process), size = 5) +
  geom_node_text(nudge_y = 0.1, size = 3.2, aes(label = eggNOG_name, colour = COG_Process)) +
  scale_edge_width(range = c(0.2, 2)) +
  theme_graph(background = "white", foreground = grey(0.5),
    plot_margin = margin(10, 10, 10, 10))

Mechanisms enabling faster growth in several conditions

The picture for these strains is more clear then for the fructose-enriched strains. 13 out of 27 enriched genes (48%), among them some of the most enriched, are directly involved in hydrogenase activity, i.e. hydrogen oxygenation (hoxA, hoxF, hoxU, hoxX, hypA, hypB, hypC, hypD hypE, hypF, hyaA, hyaB, hupH). The mechanism of enabling faster growth by KO of hydrogenases is unknown.

The second theme is enrichment of ptsI (H16_A0326) and ptsH (H16_A0325), together the entire functional unit of the PTS system, the PEP-dependent sugar phosphotransferase system (sugar PTS). “This major carbohydrate active-transport system catalyzes the phosphorylation of incoming sugar substrates concomitantly with their translocation across the cell membrane. Enzyme I transfers the phosphoryl group from (PEP) to the phosphoryl carrier protein (HPr).” Why does the KO of PTS system provides a growth benefit in in all conditions with almost equal contribution? Must be related to energy metabolism, because neither fructose (ABC transporter), succinate and def not formate are transported via a PTS.

Other interesting mechanisms: KO of RNA polymerase sigma factor RpoS (H16_A2373) seems to have a beneficial effect on steady state growth, as well as other stress related transcription factors like cold shock protein capB (H16_B2205), and scoF (H16_B0002).

The gene H16_B2043 is by far most abundant (by reads) and most enriched (by fitness) single mutant in almost all conditions. What is the mechanism? There is almost nothing known about this gene except that it probably has cyclic-guanylate-specific phosphodiesterase activity. This enzyme has, according to PFAM, two domains, the diguanylate cyclase (GGDEF) and the EAL domain. The first one synthesizes cyclic di-GMP Ryjenkov et al., J Bact, 2005. The second domain can act as phosphodiesterase and cleave cyclic cAMP or cGMP. Both compounds play a role in signaling, cAMP for example as the hormone in catabolite repression. According to the discussion in the linked paper, “Mutations in the GGDEF domain proteins or overexpression of such proteins affect exopolysaccharide synthesis […] and formation of biofilms. In C. crescentus, flagellum ejection, which is required for the switch from motile to sessile lifestyle, is impaired in a mutated GGDEF domain”. The underlying mechanism could be disrupted biofilm formation, higher flagellum activity, and thus non-settling phenotype in the bioreactor. Alternatively the mutation affects cAMP formation and disrupts or enhances catabolite repression (more likely that disrupted catabolite repression is beneficial).

Sanity checks

All above results are based on fitness score, which is not much more than a normalized log2 fold change of read count over time. We can compare if the mutants with extremely high fitness scores are also the ones that are super-abundant at the final time point, ie.e. have an average read count of >= 500,000 after 16 generations. In fact, only 3 genes have such an extreme read count, but 9 have more than 100,000 reads.

df_fitness %>% filter(Time == 16, locus_tag %in% (subset(list_enriched, list_enriched %in% c(3,4)) %>% names)) %>%
  group_by(locus_tag) %>% summarize(max_counts = max(Counts), max_fitness = max(Norm_fg)) %>%
  arrange(desc(max_counts))

On the other hand, we can check which genes have an extremely high read count (>= 500,000 in any condition) and see if this correlates with high fitness score. It does partly. 3 out of 7 highly abundant gene mutants enrich extremely over time. The other enrich too, but only 2^1 = 2 to 2^3.5 = 11 times. These non-enriching super-abundant mutants are:

  • H16_A0774 - cphA, Cyanophycin synthase. Supposed mechanism: enriches in LB medium as it does not turn Asp into cyanophycin. No benefit on minimal medium.
  • H16_B2570 - fecA, Outer membrane receptor for Fe(III). Supposed mechanism: regulator activity together with fecR, but also transmembrane transporter for siderophores. KO reduces sensitivty to excess iron??
  • H16_A3145 - Conserved protein/domain typically associated with flavoprotein oxygenases, DIM6/NTAB family. Supposed mechanism: unknown.
df_fitness %>% filter(Time == 16, Counts > 5*10^5) %>%
  group_by(locus_tag) %>% summarize(max_counts = max(Counts), max_fitness = max(Norm_fg)) %>%
  arrange(desc(max_counts))

Depletion of mutants over time (reduced fitness)

Depletion on formate

Several genes/mutants are depleted over time depending on growth condition. Most interesting in this context are cluster 1 and 2, depletion only on formate, or in all conditions, respectively. Not surprisingly, formate-specific genes are highly depleted during growth on formate, but not cbb (Calvin cycle) genes.

df_fitness_summary %>%
  filter(locus_tag %in% names(subset(list_enriched, list_enriched == 1))) %>%
  filter(Time == 16) %>%
  barchart_fitness() %>%
  print(position = c(0,0,0.6,1), more = TRUE)

df_fitness_summary %>%
  filter(locus_tag %in% names(subset(list_enriched, list_enriched == 1))) %>%
  linechart_fitness() %>%
  print(position = c(0.58,0,1,1))

What is the role of formate-essential genes? Are there patterns that emerge? We can submit the depleted gene list to STRING DB and retrieve a possible network of interactions. The network shows immediately that there are many high-scoring interactions between the genes, particularly the soluble FDH genes are sticking out as one cluster (fdsABDG) and their transcriptional regulator fdsR. Then the molybdenum cofactor processing proteins moaCDE, moeA, mobA, mog. And a range of cytochrome genes responsible for acceptance and transport of of electrons from formate to the ETC in cytoplasmic membrane (petABC, ccoGNOP, cyc). It is also intersting what is NOT essential on formate, such as no cbb genes except the master transcriptional regulator cbbR. The reason for this must be the redundancy of all cbb genes (two operons).

graph_formate_depl <- retrieve_STRING(
  gene_ID = names(subset(list_enriched, list_enriched == 1)),
  taxon_ID = 381666,
  ref = rename(df_ref, name = locus_tag)
)

graph_formate_depl %>% arrange(COG_Process) %>% activate(edges) %>% 
  filter(score >= 0.4) %>%
  ggraph(layout = 'linear', circular = TRUE) +
  geom_edge_arc(colour = grey(0.6, 0.5), aes(width = score)) + 
  geom_node_point(aes(colour = COG_Process), size = 5) +
  geom_node_text(nudge_y = 0.1, size = 3.2, aes(label = eggNOG_name, colour = COG_Process)) +
  scale_edge_width(range = c(0.2, 2)) +
  theme_graph(background = "white", foreground = grey(0.5),
    plot_margin = margin(10, 10, 10, 10))

Depletion in all conditions

Which genes are depleted in all conditions (cluster 2)? Here we see the effect of the read compression, such that many genes seem to “recover” from initial depletion and enrich from 8 to 16 generation time point. This effect is only apparent for the continuous conditions and with very high probability related to the distortion of read counts by super-enriching mutants. The 8 generation time point should be considered as more reliable in those cases.

df_fitness_summary %>%
  filter(locus_tag %in% names(subset(list_enriched, list_enriched == 2))) %>%
  filter(Time == 16) %>%
  barchart_fitness() %>%
  print(position = c(0,0,0.6,1), more = TRUE)

df_fitness_summary %>%
  filter(locus_tag %in% names(subset(list_enriched, list_enriched == 2))) %>%
  linechart_fitness() %>%
  print(position = c(0.58,0,1,1))

graph_all_depl <- retrieve_STRING(
  gene_ID = names(subset(list_enriched, list_enriched == 2)),
  taxon_ID = 381666,
  ref = rename(df_ref, name = locus_tag)
)

graph_all_depl %>% arrange(COG_Process) %>% activate(edges) %>% 
  filter(score >= 0.4) %>%
  ggraph(layout = 'linear', circular = TRUE) +
  geom_edge_arc(colour = grey(0.6, 0.5), aes(width = score)) + 
  geom_node_point(aes(colour = COG_Process), size = 5) +
  geom_node_text(nudge_y = 0.1, size = 3.2, aes(label = eggNOG_name, colour = COG_Process)) +
  scale_edge_width(range = c(0.2, 2)) +
  theme_graph(background = "white", foreground = grey(0.5),
    plot_margin = margin(10, 10, 10, 10))

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgY29tcGV0aXRpb24gZXhwZXJpbWVudHMgd2l0aCBhIGJhcmNvZGVkIHRyYW5zcG9zb24gbGlicmFyeSIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgphdXRob3I6ICJNaWNoYWVsIEphaG4iCm91dHB1dDoKICBodG1sX25vdGVib29rOiAKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB5ZXMKLS0tCgojIyBEZXNjcmlwdGlvbgoKVGhpcyBSIG5vdGVib29rIGlzIGEgYmlvaW5mb3JtYXRpY3MgcGlwZWxpbmUgdG8gYW5hbHl6ZSBmaXRuZXNzIGRhdGEgb2J0YWluZWQgZnJvbSBhIGJhcmNvZGVkIHRyYW5zcG9zb24gbGlicmFyeSBpbiAqUmFsc3RvbmlhIGV1dHJvcGhhKiBhLmsuYS4gKkN1cHJpYXZpZHVzIG5lY2F0b3IqLiBGb3IgYmFja2dyb3VuZCBhbmQgZGV0YWlscyByZWdhcmRpbmcgdGhlIG1ldGhvZCwgc2VlIFtXZXRtb3JlIGF0IGFsLiwgbUJpbywgMjAxNV0oaHR0cHM6Ly9tYmlvLmFzbS5vcmcvY29udGVudC82LzMvZTAwMzA2LTE1KSBhbmQgW1ByaWNlIGV0IGFsLiwgTmF0dXJlLCAyMDE4XShodHRwOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTg2LTAxOC0wMTI0LTApKS4KCgojIyBMaWJyYXJpZXMKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9CiMgb3B0aW9uYWxseSBpbnN0YWxsIHJlcG9zIGZyb20gZ2l0aHViCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJtLWphaG4vbGF0dGljZS10b29scyIpCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJtLWphaG4vUi10b29scyIpCmxpYnJhcnkobGF0dGljZSkKbGlicmFyeShsYXR0aWNlRXh0cmEpCmxpYnJhcnkobGF0dGljZXRvb2xzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkZW5kZXh0ZW5kKQpsaWJyYXJ5KFJ0b29scykKbGlicmFyeShjb2xvcnNwYWNlKQpgYGAKCgojIyBPdmVydmlldyBvZiBiYXJjb2RlL3RyYW5zcG9zb24gcmVhZCBjb3VudHMKCiMjIyBEYXRhIGltcG9ydCBhbmQgcHJvY2Vzc2luZwoKUmVhZCBpbiB0aGUgbWFpbiBkYXRhIHRhYmxlcyB3aXRoIEEpIHJlYWRzIHBlciBiYXJjb2RlIGFuZCBzYW1wbGUgKCdwb29sIGNvdW50cycpLCBhbmQgQikgdGhlIGZpdG5lc3MgdGFibGVzLiBUYWJsZXMgd2VyZSBvYnRhaW5lZCBieSBwcm9jZXNzaW5nIHNlcXVlbmNpbmcgZGF0YSB3aXRoIGEgY3VzdG9tIFtCYXJTZXEgcGlwZWxpbmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9tLWphaG4vcmViYXIpLiBUaGUgMzIgZ2VuZXJhdGlvbiBzZXF1ZW5jaW5nIHNhbXBsZXMgYXJlIHJlbW92ZWQgZHVlIHRvIHRoZSBsb3cgcmVhZCBjb3VudCBpbiB0aGUgYGNvbnRpbnVvdXNgIHNhbXBsZXMuCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQojIGltcG9ydCBiYXJzZXEgY291bnRzIGRhdGEgaW4gd2lkZSBmb3JtYXQgYW5kIHJlc2hhcGUgdG8gbG9uZyBmb3JtYXQKZGZfY291bnRzX2ZyYyA8LSByZWFkX3RzdigiLi4vLi4vLi4vcmViYXIvZGF0YS8yMDIwMTIyMl9iYXJzZXFfZnJjL3Jlc3VsdHMvcmVzdWx0LnBvb2xjb3VudCIpICU+JQogIHNlbGVjdCghbWF0Y2hlcygiMzJnZW58XzMyXyIpKSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gIWFsbF9vZihjKCJiYXJjb2RlIiwgInJjYmFyY29kZSIsICJzY2FmZm9sZCIsICJzdHJhbmQiLCAicG9zIikpLCAKICAgIG5hbWVzX3RvID0gInNhbXBsZSIsIHZhbHVlc190byA9ICJuX3JlYWRzIikKCmRmX2NvdW50c19zdWMgPC0gcmVhZF90c3YoIi4uLy4uLy4uL3JlYmFyL2RhdGEvMjAyMTA0MDdfYmFyc2VxX3N1Y19mb3IvcmVzdWx0cy9yZXN1bHQucG9vbGNvdW50IikgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9ICFhbGxfb2YoYygiYmFyY29kZSIsICJyY2JhcmNvZGUiLCAic2NhZmZvbGQiLCAic3RyYW5kIiwgInBvcyIpKSwgCiAgICBuYW1lc190byA9ICJzYW1wbGUiLCB2YWx1ZXNfdG8gPSAibl9yZWFkcyIpCgojIG1lcmdlIGJhcmNvZGUgY291bnRzIHRhYmxlcwpkZl9jb3VudHMgPC0gYmluZF9yb3dzKGRmX2NvdW50c19mcmMsIGRmX2NvdW50c19zdWMpCgojIGltcG9ydCBmaXRuZXNzIGRhdGEsIHRoZSBmaW5hbCBvdXRwdXQgb2YgdGhlIEJhclNlcSBwaXBlbGluZQpsb2FkKCIuLi8uLi8uLi9yZWJhci9kYXRhLzIwMjAxMjIyX2JhcnNlcV9mcmMvcmVzdWx0cy9maXRuZXNzX2dlbmUuUmRhdGEiKQpkZl9maXRuZXNzX2ZyYyA8LSBmaXRuZXNzX2dlbmUgJT4lCiAgZmlsdGVyKENvbmRpdGlvbiAhPSAibG9uZyBwdWxzZSIsIFRpbWUgIT0gMzIpICU+JQogIG11dGF0ZShJRCA9IGFzLm51bWVyaWMoSUQpLCBTdWJzdHJhdGUgPSAiZnJ1Y3Rvc2UiLCAKICAgIENvbmRpdGlvbiA9IHN0cl9yZW1vdmUoQ29uZGl0aW9uLCAic2hvcnQgIikpCgpsb2FkKCIuLi8uLi8uLi9yZWJhci9kYXRhLzIwMjEwNDA3X2JhcnNlcV9zdWNfZm9yL3Jlc3VsdHMvZml0bmVzc19nZW5lLlJkYXRhIikKZGZfZml0bmVzc19zdWMgPC0gZml0bmVzc19nZW5lICU+JQogIHNlcGFyYXRlKENvbmRpdGlvbiwgc2VwID0gIl8iLCBpbnRvID0gYygiU3Vic3RyYXRlIiwgIkNvbmRpdGlvbiIpKQoKIyBtZXJnZSBmaXRuZXNzIHRhYmxlcwpkZl9maXRuZXNzIDwtIGJpbmRfcm93cyhkZl9maXRuZXNzX2ZyYywgZGZfZml0bmVzc19zdWMpICU+JQogIHJlbmFtZShsb2N1c190YWcgPSBsb2N1c0lkKQpybSgiZGZfZml0bmVzc19mcmMiLCAiZGZfZml0bmVzc19zdWMiLCAiZGZfY291bnRzX2ZyYyIsICJkZl9jb3VudHNfc3VjIikKCiMgaW1wb3J0IGdlbm9tZSBhbm5vdGF0aW9uCmRmX3JlZiA8LSByZWFkX2NzdigiLi4vZGF0YS9yZWYvUmFsc3RvbmlhX0gxNl9nZW5vbWVfYW5ub3RhdGlvbi5jc3YiKSAlPiUKICBmaWx0ZXIoIWR1cGxpY2F0ZWQobG9jdXNfdGFnKSkgJT4lCiAgbXV0YXRlKGVnZ05PR19uYW1lID0gaWZfZWxzZShpcy5uYShlZ2dOT0dfbmFtZSksIGdlbmVfbmFtZSwgZWdnTk9HX25hbWUpKQoKIyBkZWZpbmUgc3RhbmRhcmQgY29sb3JzCnN0ZGNvbCA8LSBjdXN0b20uY29sb3JibGluZCgpJHN1cGVycG9zZS5saW5lJGNvbApgYGAKCiMjIyBTdW1tYXJ5IHN0YXRpc3RpY3MKCk92ZXJ2aWV3IGFib3V0IHRoZSBudW1iZXIgb2YgcmVhZHMgcGVyIGJhcmNvZGUsIGJhcmNvZGVzIHBlciBnZW5lIGFuZCBzbyBvbi4gQXJvdW5kIDgtMTAgTSByZWFkcyB3ZXJlIG1hcHBlZCBvbiBhdmVyYWdlLCBwZXIgc2FtcGxlLiAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOCwgbWVzc2FnZSA9IEZBTFNFfQojIE51bWJlciBvZiB0b3RhbCBtYXBwZWQgcmVhZHMKZGZfY291bnRzICU+JSBncm91cF9ieShzYW1wbGUpICU+JQogIHN1bW1hcml6ZShuX21pbGxpb25fcmVhZHMgPSBzdW0obl9yZWFkcykvMTBeNikgJT4lCiAgYmFyY2hhcnQoZmFjdG9yKHNhbXBsZSkgfiBuX21pbGxpb25fcmVhZHMsIC4sCiAgICBwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpLAogICAgaG9yaXpvbnRhbCA9IFRSVUUsIGJvcmRlciA9IE5VTEwsCiAgICBzY2FsZXMgPSBsaXN0KHkgPSBsaXN0KGNleCA9IDAuNykpLAogICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCAuLi4pIHsKICAgICAgcGFuZWwuZ3JpZChoID0gLTEsIHYgPSAtMSwgY29sID0gZ3JleSgwLjkpKQogICAgICBwYW5lbC5iYXJjaGFydCh4LCB5LCAuLi4pCiAgICB9CiAgKQpgYGAKCkRpc3RyaWJ1dGlvbiBvZiAqKm51bWJlciBvZiByZWFkcyBwZXIgYmFyY29kZSoqLiBUaGVyZSBpcyBhIHN1ZmZpY2llbnQgbnVtYmVyIG9mIHJlYWRzIGZvciBxdWFudGlmaWNhdGlvbiwgb24gYXZlcmFnZSBsb2cyKG4pID0gNSA9IDMyIHJlYWRzIHBlciBiYXJjb2RlLgoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2LjJ9CnBsb3RfcmVhZHNfcGVyX2JjIDwtIGhpc3RvZ3JhbSh+IGxvZzIobl9yZWFkcykgfCBzYW1wbGUsCiAgZGZfY291bnRzLCBhcy50YWJsZSA9IFRSVUUsIGxheW91dCA9IGMoOCw2KSwKICBwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpLAogIGJldHdlZW4gPSBsaXN0KHggPSAwLjUsIHkgPSAwLjUpLAogIHhsYWIgPSBleHByZXNzaW9uKCJsb2ciWzJdKiIgcmVhZHMgcGVyIGJhcmNvZGUiKSwKICBzY2FsZXMgPSBsaXN0KGFsdGVybmF0aW5nID0gRkFMU0UpLAogIHBhbmVsID0gZnVuY3Rpb24oeCwgLi4uKSB7CiAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICBwYW5lbC5oaXN0b2dyYW0oeCwgYm9yZGVyID0gIndoaXRlIiwgLi4uKQogIH0KKQoKcHJpbnQocGxvdF9yZWFkc19wZXJfYmMpCmBgYAoKU2ltaWxhcmx5IHRvIHRoZSBhYm92ZSwgdGhpcyBpcyBhbiBvdmVydmlldyBhYm91dCB0aGUgKipudW1iZXIgb2YgYmFyY29kZXMgcGVyIGdlbmUqKiBhcyBhIGhpc3RvZ3JhbS4gVGhpcyBkaXN0cmlidXRpb24gaXMgdGhlIHNhbWUgZm9yIGFsbCBjb25kaXRpb25zIGFuZCByZXBsaWNhdGVzLiBUaGUgc2Vjb25kIHBsb3QgaXMgdGhlICoqbnVtYmVyIG9mIHJlYWRzIHBlciBnZW5lKiosIGF2ZXJhZ2VkIGFzIG1lZGlhbiBvdmVyIGFsbCBjb25kaXRpb25zIChleGNsdWRpbmcgMCB0aW1lIHBvaW50IHdoZXJlIGNvdW50cyB3ZXJlIGF2ZXJhZ2VkIGJ5IEJhclNlcSBwaXBlbGluZSkuIFRoZSBhdmVyYWdlIHJlYWRzIHBlciBnZW5lIGFyZSBsb2cyKG4pID0gOCwgd2hpY2ggdHJhbnNsYXRlcyB0byBuID0gMl44IG9yIGFyb3VuZCAyNTYgcmVhZHMgcGVyIGdlbmUuCgoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA0LjIsIG1lc3NhZ2UgPSBGQUxTRX0KcGxvdF9yZWFkc19wZXJfYmMgPC0gaGlzdG9ncmFtKH4gU3RyYWluc19wZXJfZ2VuZSwKICBkZl9maXRuZXNzICU+JSBzZWxlY3QobG9jdXNfdGFnLCBTdHJhaW5zX3Blcl9nZW5lKSAlPiUgCiAgICBkaXN0aW5jdCAlPiUgZmlsdGVyKFN0cmFpbnNfcGVyX2dlbmUgPCA0MCksIAogIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksIGJyZWFrcyA9IDIwLCB4bGltPWMoLTIsIDQyKSwKICB4bGFiID0gZXhwcmVzc2lvbigibXV0YW50cyBwZXIgZ2VuZSIpLAogIHBhbmVsID0gZnVuY3Rpb24oeCwgLi4uKSB7CiAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICBwYW5lbC5oaXN0b2dyYW0oeCwgYm9yZGVyID0gIndoaXRlIiwgLi4uKQogICAgcGFuZWwuYWJsaW5lcSh2ID0gbWVhbih4LCBuYS5ybSA9IFRSVUUpLAogICAgICBmb250ZmFtaWx5ID0gIkZyZWVTYW5zIiwgY29sID0gZ3JleSgwLjUpLCBsd2QgPSAyLCBsdHkgPSAyKQogIH0KKQoKcGxvdF9yZWFkc19wZXJfZ2VuZSA8LSBoaXN0b2dyYW0ofiBsb2cyKHJlYWRzX3Blcl9nZW5lX21lZGlhbiksCiAgZGZfZml0bmVzcyAlPiUgZmlsdGVyKFRpbWUgIT0gMCkgJT4lIGdyb3VwX2J5KGxvY3VzX3RhZykgJT4lCiAgICBzdW1tYXJpemUocmVhZHNfcGVyX2dlbmVfbWVkaWFuID0gbWVkaWFuKENvdW50cykpLAogIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksIGJyZWFrcyA9IDIwLAogIHhsYWIgPSBleHByZXNzaW9uKCJsb2ciWzJdKiIgcmVhZHMgcGVyIGdlbmUgKG1lZCkiKSwKICBwYW5lbCA9IGZ1bmN0aW9uKHgsIC4uLikgewogICAgcGFuZWwuZ3JpZChoID0gLTEsIHYgPSAtMSwgY29sID0gZ3JleSgwLjkpKQogICAgcGFuZWwuaGlzdG9ncmFtKHgsIGJvcmRlciA9ICJ3aGl0ZSIsIC4uLikKICAgIHBhbmVsLmFibGluZXEodiA9IG1lYW4oeFshaXMuaW5maW5pdGUoeCldKSwKICAgICAgZm9udGZhbWlseSA9ICJGcmVlU2FucyIsIGNvbCA9IGdyZXkoMC41KSwgbHdkID0gMiwgbHR5ID0gMikKICB9CikKCnByaW50KHBsb3RfcmVhZHNfcGVyX2JjLCBzcGxpdCA9IGMoMSwxLDIsMSksIG1vcmUgPSBUUlVFKQpwcmludChwbG90X3JlYWRzX3Blcl9nZW5lLCBzcGxpdCA9IGMoMiwxLDIsMSkpCmBgYAoKIyMgR2VuZSBmaXRuZXNzIGFuYWx5c2lzCgojIyMgRGVwbGV0aW9uIG92ZXIgdGltZSAoZ2VuZXJhdGlvbnMpCgpXZSBjYW4gcGxvdCBsb2cyIEZDIG9yIG5vcm1hbGl6ZWQgZ2VuZSBmaXRuZXNzIG92ZXIgZ2VuZXJhdGlvbnMuIEZvciB0aGlzIHR5cGUgb2Ygb3ZlcnZpZXcgaXQgaXMgYmVzdCB0byBzdW1tYXJpemUgaW5kaXZpZHVhbCByZXBsaWNhdGVzICg0eCkgdG8gdGhlIG1lYW4gb3IgbWVkaWFuLCBwZXIgdGltZSBwb2ludCBhbmQgY29uZGl0aW9uLiBXZSBhbHNvIGFkZCBnZW5vbWUgYW5ub3RhdGlvbiB0byB0aGUgc3VtbWFyeSB0YWJsZS4gVGhlIHBsb3RzIHNob3dzIHRoYXQgZGVwbGV0aW9uIG9mIHNvbWUgc3RyYWlucyBpcyBzbyBzdHJvbmcgYWxyZWFkeSBhdCA4IGdlbmVyYXRpb25zIHRoYXQgZml0bmVzcy9sb2cyIEZDIGNvdWxkIG5vdCBiZSBxdWFudGlmaWVkIGZvciAxNiBnZW5lcmF0aW9ucyBkdWUgdG8gbWlzc2luZyByZWFkIGNvdW50cy4gSXQgaXMgYmVzdCB0byBmb2N1cyBvbiA4IGdlbmVyYXRpb25zIGFzIGJlY2F1c2UgaXQgcHJvdmlkZXMgYSBtb3JlIGNvbXBsZXRlIHBpY3R1cmUuCgpgYGB7ciwgbWVzc2FnZXMgPSBGQUxTRX0KZGZfZml0bmVzc19zdW1tYXJ5IDwtIGRmX2ZpdG5lc3MgJT4lCiAgZ3JvdXBfYnkobG9jdXNfdGFnLCBzY2FmZm9sZCwgVGltZSwgQ29uZGl0aW9uLCBTdWJzdHJhdGUsIFN0cmFpbnNfcGVyX2dlbmUpICU+JQogIHN1bW1hcml6ZSgKICAgIE5vcm1fZmdfbWVkaWFuID0gbWVkaWFuKE5vcm1fZmcsIG5hLnJtID0gVFJVRSksCiAgICBsb2cyRkNfbWVkaWFuID0gbWVkaWFuKGxvZzJGQywgbmEucm0gPSBUUlVFKSwKICAgIHRzdGF0X21lZGlhbiA9IG1lZGlhbih0LCBuYS5ybSA9IFRSVUUpCiAgKSAlPiUKICBsZWZ0X2pvaW4oZGZfcmVmKQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoID0gNi41LCBmaWcuaGVpZ2h0ID0gOH0KcGxvdF9oaXN0X2xvZzJGQyA8LSBkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgZmlsdGVyKGFsbCghaXMuaW5maW5pdGUobG9nMkZDX21lZGlhbikpKSAlPiUKICBncm91cF9ieShDb25kaXRpb24sIFN1YnN0cmF0ZSkgJT4lCiAgc2xpY2UoMToyMDAwKSAlPiUKICAKICB4eXBsb3QobG9nMkZDX21lZGlhbiB+IFRpbWUgfCBTdWJzdHJhdGUgKiBDb25kaXRpb24sIC4sCiAgICBncm91cHMgPSBsb2N1c190YWcsIGFzLnRhYmxlID0gVFJVRSwKICAgIGNvbCA9IHN0ZGNvbFsxXSwgYWxwaGEgPSAwLjIsIGxheW91dCA9IGMoMywgMiksCiAgICB4bGFiID0gIiIsIHlsYWIgPSBleHByZXNzaW9uKCJsb2ciWzJdKiIgRkMiKSwKICAgIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksIHR5cGUgPSBjKCJsIiksCiAgICBiZXR3ZWVuID0gbGlzdCh4ID0gMC41LCB5ID0gMC41KSwKICAgIHNjYWxlcyA9IGxpc3QoYWx0ZXJuYXRpbmcgPSBGQUxTRSksIGx3ZCA9IDIsCiAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIC4uLikgewogICAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICAgIHBhbmVsLnh5cGxvdCh4LCB5LCAuLi4pCiAgICB9CiAgKQoKcGxvdF9oaXN0X25vcm1mZyA8LSBkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgZmlsdGVyKGFsbCghaXMuaW5maW5pdGUobG9nMkZDX21lZGlhbikpKSAlPiUKICBncm91cF9ieShDb25kaXRpb24sIFN1YnN0cmF0ZSkgJT4lCiAgc2xpY2UoMToyMDAwKSAlPiUKICAKICB4eXBsb3QoTm9ybV9mZ19tZWRpYW4gfiBUaW1lIHwgU3Vic3RyYXRlICogQ29uZGl0aW9uLCAuLAogICAgZ3JvdXBzID0gbG9jdXNfdGFnLCBhcy50YWJsZSA9IFRSVUUsCiAgICBjb2wgPSBzdGRjb2xbMl0sIGFscGhhID0gMC4yLCBsYXlvdXQgPSBjKDMsIDIpLAogICAgeGxhYiA9ICJnZW5lcmF0aW9ucyIsIHlsYWIgPSAiZml0bmVzcyIsCiAgICBwYXIuc2V0dGluZ3MgPSBjdXN0b20uY29sb3JibGluZCgpLCB0eXBlID0gYygibCIpLAogICAgYmV0d2VlbiA9IGxpc3QoeCA9IDAuNSwgeSA9IDAuNSksCiAgICBzY2FsZXMgPSBsaXN0KGFsdGVybmF0aW5nID0gRkFMU0UpLCBsd2QgPSAyLAogICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCAuLi4pIHsKICAgICAgcGFuZWwuZ3JpZChoID0gLTEsIHYgPSAtMSwgY29sID0gZ3JleSgwLjkpKQogICAgICBwYW5lbC54eXBsb3QoeCwgeSwgLi4uKQogICAgfQogICkKCnByaW50KHBsb3RfaGlzdF9sb2cyRkMsIHBvc2l0aW9uID0gYygwLDAuNDcsMSwxKSwgbW9yZSA9IFRSVUUpCnByaW50KHBsb3RfaGlzdF9ub3JtZmcsIHBvc2l0aW9uID0gYygwLDAsMSwwLjUzKSkKYGBgCgpBcyBzb3J0IG9mIGFuIGludGVybmFsIGNvbnRyb2wsIHdlIGNvbXBhcmUgdGhlIGdlbmUgZml0bmVzcyBvYnRhaW5lZCBieSBhIGNvbXBsZXggcHJvY2VkdXJlIHRvIHRoZSBsb2cyIEZDIG9mIHJlYWQgY291bnRzLCB3aGljaCBpcyBhIHZlcnkgc2ltcGxlIG1lYXN1cmUgb2YgJ2ZpdG5lc3MnLiBUaGUgdHdvIHZhcmlhYmxlcyBjb3JyZWxhdGUgd2VsbCBhbGwgdGVzdGVkIGNvbmRpdGlvbnMgYW5kIHN1YnN0cmF0ZXMuCgpgYGB7ciwgZmlnLndpZHRoID0gNi41LCBmaWcuaGVpZ2h0ID0gNS4yfQpkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgZmlsdGVyKFRpbWUgPT0gOCwgYWxsKCFpcy5pbmZpbml0ZShsb2cyRkNfbWVkaWFuKSkpICU+JQogIAogIHh5cGxvdChOb3JtX2ZnX21lZGlhbiB+IGxvZzJGQ19tZWRpYW4gfCAgU3Vic3RyYXRlICogQ29uZGl0aW9uLCAuLAogICAgYXMudGFibGUgPSBUUlVFLCBjb2wgPSBzdGRjb2xbNV0sIHBjaCA9IDE5LAogICAgYWxwaGEgPSAwLjQsIGNleCA9IDAuNiwKICAgIGxheW91dCA9IGMoMywgMiksIHhsaW0gPSBjKC04LDMpLCB5bGltID0gYygtNiw1KSwKICAgIHhsYWIgPSBleHByZXNzaW9uKCJsb2ciWzJdKiIgRkMiKSwgeWxhYiA9ICJmaXRuZXNzIiwKICAgIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksCiAgICBiZXR3ZWVuID0gbGlzdCh4ID0gMC41LCB5ID0gMC41KSwKICAgIHNjYWxlcyA9IGxpc3QoYWx0ZXJuYXRpbmcgPSBGQUxTRSksCiAgICBwYW5lbCA9IGZ1bmN0aW9uKHgsIHksIC4uLikgewogICAgICBwYW5lbC5ncmlkKGggPSAtMSwgdiA9IC0xLCBjb2wgPSBncmV5KDAuOSkpCiAgICAgIHBhbmVsLnh5cGxvdCh4LCB5LCAuLi4pCiAgICAgIHBhbmVsLmxtbGluZXEoeCwgeSwgZm9udGZhbWlseSA9ICJGcmVlU2FucyIsIHIuc3F1YXJlZCA9IFRSVUUsIGx3ZCA9IDEuNSwgCiAgICAgICAgY29sLnRleHQgPSAxLCBwb3MgPSAzLCBvZmZzZXQgPSA1LCAuLi4pCiAgICAgIHBhbmVsLmFibGluZShhID0gMiwgYiA9IDEsIGNvbCA9IGdyZXkoMC41KSwgbHR5ID0gMiwgbHdkID0gMS41KQogICAgfQogICkKYGBgCgojIyMgQ29tcGFyaW5nIGdlbmUgZml0bmVzcyBiZXR3ZWVuIGNvbmRpdGlvbnMKClNpbWlsYXJseSB0byBGaWd1cmUgMiBpbiBbV2V0bW9yZSBldCBhbCwgbUJJTywgMjAxNV0oaHR0cHM6Ly9tYmlvLmFzbS5vcmcvY29udGVudC82LzMvZTAwMzA2LTE1KSwgd2UgY2FuIGludmVzdGlnYXRlIGNvbmRpdGlvbi1kZXBlbmRlbnQgZ2VuZSBmaXRuZXNzIGJ5IGNvbXBhcmluZyBjb25kaXRpb25zIGFuZCBzdWJzdHJhdGVzIG9uZS1vbi1vbmUuIFRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHN1YnN0cmF0ZXMgYW5kIGdyb3d0aCByZWdpbWVzIChjb250aW51b3VzLCBwdWxzZWQpIGlzIHF1aXRlIGRpZmZlcmVudC4gVGhlIHN0cm9uZ2VzdCBjb3JyZWxhdGlvbiBkb2VzIGV4aXN0IGZvciB0aGUgcHVsc2VkIHZzIGNvbnRpbnVvdXMgcmVnaW1lIGZvciBlYWNoIHN1YnN0cmF0ZSAoUiA9IDAuNjQgdG8gMC44NykuIEFuZCBmb3IgdGhlIHB1bHNlZCBjb25kaXRpb25zLCBjb21wYXJpc29uIGJldHdlZW4gc3Vic3RyYXRlcyAoUiA9IDAuNjIgdG8gMC43MikuCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDgsIG1lc3NhZ2UgPSBGQUxTRX0KZGZfZml0bmVzc19jb21wIDwtIGRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUgZmlsdGVyKFRpbWUgPT0gOCkgJT4lCiAgZ3JvdXBfYnkobG9jdXNfdGFnKSAlPiUgbXV0YXRlKHRzdGF0X21lZGlhbiA9IG1pbih0c3RhdF9tZWRpYW4pKSAlPiUKICBzZWxlY3QobG9jdXNfdGFnLCBDb25kaXRpb24sIFN1YnN0cmF0ZSwgTm9ybV9mZ19tZWRpYW4sIGdlbmVfbmFtZSwgQ09HX1Byb2Nlc3MsIHRzdGF0X21lZGlhbikgJT4lCiAgdW5pdGUoQ29uZGl0aW9uLCBDb25kaXRpb24sIFN1YnN0cmF0ZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IENvbmRpdGlvbiwgdmFsdWVzX2Zyb20gPSBOb3JtX2ZnX21lZGlhbikgJT4lCiAgZmlsdGVyKCFpcy5uYShsb2N1c190YWcpKQoKY3VzdG9tX3NwbG9tKGRmX2ZpdG5lc3NfY29tcCAlPiUgdW5ncm91cCAlPiUgCiAgc2VsZWN0KG1hdGNoZXMoImNvbnRpfHB1bHNlIikpLCBjb2wgPSBncmV5KDAuNCwgMC40KSkKYGBgCgpXZSBjYW4gYWxzbyBjb21wYXJlIHNlbGVjdGVkIGNvbmRpdGlvbnMgZGlyZWN0bHkgdG8gaWRlbnRpZnkgZ2VuZXMgZW5yaWNoZWQgb3IgZGVwbGV0ZWQgaW4gc2V2ZXJhbCBjb25kaXRpb25zLgoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4LCBtZXNzYWdlID0gRkFMU0V9CiMgZ2VuZXJhbGl6ZWQgcGxvdHRpbmcgZnVuY3Rpb24KcGxvdF9maXRuZXNzX2NvbXAgPC0gZnVuY3Rpb24oZGF0YSwgdmFycyl7CiAgeHlwbG90KGdldCh2YXJzWzJdKSB+IGdldCh2YXJzWzFdKSwgZGF0YSwKICAgIGdyb3VwcyA9IGFicyhnZXQodmFyc1sxXSktZ2V0KHZhcnNbMl0pKSA+IDIsICN0c3RhdF9tZWRpYW4gPCAtMwogICAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwgY29sID0gc3RkY29sW2MoNSwxKV0sCiAgICBwY2ggPSAxOSwgYWxwaGEgPSAwLjUsIGNleCA9IDAuNywgYXNwZWN0ID0gMSwKICAgIHhsaW0gPSBjKC03LCA0KSwgeWxpbSA9IGMoLTcsIDQpLAogICAgeGxhYiA9IHZhcnNbMV0sIHlsYWIgPSB2YXJzWzJdLAogICAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCAuLi4pIHsKICAgICAgcGFuZWwuZ3JpZChoID0gLTEsIHYgPSAtMSwgY29sID0gZ3JleSgwLjkpKQogICAgICBwYW5lbC5hYmxpbmUodiA9IDAsIGggPSAwLCBjb2wgPSBncmV5KDAuNSksIGx0eSA9IDIsIGx3ZCA9IDEuNSkKICAgICAgcGFuZWwuYWJsaW5lKGEgPSAwLCBiID0gMSwgY29sID0gZ3JleSgwLjUpLCBsdHkgPSAyLCBsd2QgPSAxLjUpCiAgICAgIHBhbmVsLmFibGluZShhID0gMiwgYiA9IDEsIGNvbCA9IGdyZXkoMC41KSwgbHR5ID0gMiwgbHdkID0gMS41KQogICAgICBwYW5lbC5hYmxpbmUoYSA9IC0yLCBiID0gMSwgY29sID0gZ3JleSgwLjUpLCBsdHkgPSAyLCBsd2QgPSAxLjUpCiAgICAgIHBhbmVsLnh5cGxvdCh4LCB5LCAuLi4pCiAgICAgIHBhbmVsLmtleSguLi4pCiAgICB9CiAgKQp9CgpwbG90X2ZpdG5lc3NfY29tcChkZl9maXRuZXNzX2NvbXAsIGMoImNvbnRpbnVvdXNfZm9ybWF0ZSIsICJwdWxzZV9mb3JtYXRlIikpICU+JQogIHByaW50KHBvc2l0aW9uID0gYygwLDAuNSwwLjUsMSksIG1vcmUgPSBUUlVFKQpwbG90X2ZpdG5lc3NfY29tcChkZl9maXRuZXNzX2NvbXAsIGMoImNvbnRpbnVvdXNfZnJ1Y3Rvc2UiLCAicHVsc2VfZnJ1Y3Rvc2UiKSkgJT4lCiAgcHJpbnQocG9zaXRpb24gPSBjKDAuNSwwLjUsMSwxKSwgbW9yZSA9IFRSVUUpCnBsb3RfZml0bmVzc19jb21wKGRmX2ZpdG5lc3NfY29tcCwgYygiY29udGludW91c19zdWNjaW5hdGUiLCAicHVsc2Vfc3VjY2luYXRlIikpICU+JQogIHByaW50KHBvc2l0aW9uID0gYygwLDAsMC41LDAuNSksIG1vcmUgPSBUUlVFKQpwbG90X2ZpdG5lc3NfY29tcChkZl9maXRuZXNzX2NvbXAsIGMoImNvbnRpbnVvdXNfZm9ybWF0ZSIsICJjb250aW51b3VzX2ZydWN0b3NlIikpICU+JQogIHByaW50KHBvc2l0aW9uID0gYygwLjUsMCwxLDAuNSksIG1vcmUgPSBUUlVFKQpgYGAKCiMjIyBEaWZmZXJlbnRpYWwgZml0bmVzcyBvZiBzZWxlY3RlZCBnZW5lcwoKTW9zdCBnZW5lcyBjb3JyZWxhdGUgaW4gZml0bmVzcyB2YWx1ZSBiZXR3ZWVuIGNvbmRpdGlvbnMuIFRoYXQgbWVhbnMsIG9ubHkgc29tZSBnZW5lcyBoYXZlIGEgKipjb25kaXRpb24tc3BlY2lmaWMgZml0bmVzcyBlZmZlY3QqKiwgaS5lLiBpbmNyZWFzZSBvciBkZWNyZWFzZSBmaXRuZXNzIG9mIHRoZSByZXNwZWN0aXZlIHN0cmFpbiBpbiBvbmUgc3Vic3RyYXRlIG9yIGdyb3d0aCByZWdpbWUgc3BlY2lmaWNhbGx5LiBUaGlzIHNlY3Rpb24gaW52ZXN0aWdhdGVzIHNwZWNpZmljIGdlbmVzIGFuZCB0aGVpciBmdW5jdGlvbnMgdGhhdCBzaG93IHN1Y2ggZGlmZmVyZW50aWFsIGZpdG5lc3MgYmV0d2VlbiBjb25kaXRpb25zLiBBIHNpbXBsZSBjb21wYXJpc29uIG9mIG9uZSBjb25kaXRpb24gdmVyc3VzIGFub3RoZXIgd2lsbCBub3QgYmUgaGVscGZ1bCBhcyB0aGVyZSB0d28gbWFueSBwb3NzaWJsZSBjb21iaW5hdGlvbnMuIFRvIGlkZW50aWZ5IGludGVyZXN0aW5nIHNldHMgb2YgZ2VuZXMsIGNsdXN0ZXIgYW5hbHlzaXMgY2FuIGJlIHBlcmZvcm1lZC4KCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDIuNX0KIyBnZW5lcmF0ZSBjb2xvcnBhbGV0dGUgZm9yIGhlYXRtYXAKaGVhdF9jb2xzIDwtIGNvbG9yc3BhY2U6OmRpdmVyZ2luZ19oY2wobiA9IDcsIGggPSBjKDI2MCwgMCksIGMgPSAxMDAsIGwgPSBjKDUwLCA5MCkpCgojIGNyZWF0ZSBhIG1hdHJpeCBmcm9tIHdpZGUgZml0bmVzcyBkYXRhIGZvciBwbG90dGluZyBoZWF0bWFwCm1hdF9oZWF0bWFwIDwtIGRmX2ZpdG5lc3NfY29tcCAlPiUgdW5ncm91cCAlPiUKICBmaWx0ZXIoaWZfYW55KC5jb2xzID0gbWF0Y2hlcygiY29udGl8cHVsc2UiKSwgfiAhYmV0d2VlbiguLCAtMiwgMikpKSAlPiUKICBzZWxlY3QobWF0Y2hlcygibG9jdXNfdGFnfGNvbnRpfHB1bHNlIikpICU+JQogICMgZmlsdGVyIG91dCBOQSByb3dzLCBhbmQgcmVwbGFjZSBleHRyZW1lIHZhbHVlcwogIGRyb3BfbmEgJT4lIG11dGF0ZShhY3Jvc3MobWF0Y2hlcygiY29udGl8cHVsc2UiKSwgCiAgICBmdW5jdGlvbih4KSB7eSA9IHJlcGxhY2UoeCwgeCA+IDYsIDYpOyByZXBsYWNlKHksIHkgPCAtNiwgLTYpfSkpICU+JQogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAibG9jdXNfdGFnIikgJT4lCiAgYXMubWF0cml4CgojIGNyZWF0ZSBjbHVzdGVyIGZvciByZW9yZGVyaW5nCm1hdF9jbHVzdGVyIDwtIG1hdF9oZWF0bWFwICU+JSBkaXN0ICU+JSBoY2x1c3QobWV0aG9kID0gIndhcmQuRCIpCm1hdF9oZWF0bWFwIDwtIG1hdF9oZWF0bWFwW29yZGVyLmRlbmRyb2dyYW0oYXMuZGVuZHJvZ3JhbShtYXRfY2x1c3RlcikpLCBjKDEsNCwyLDUsMyw2KV0KCiMgcGxvdCBoZWF0bWFwCnBsb3RfaGVhdG1hcCA8LSBsZXZlbHBsb3QobWF0X2hlYXRtYXAsCiAgcGFyLnNldHRpbmdzID0gY3VzdG9tLmNvbG9yYmxpbmQoKSwKICBjb2wucmVnaW9ucyA9IGNvbG9yUmFtcFBhbGV0dGUoaGVhdF9jb2xzKSgxNiksCiAgYXQgPSBzZXEoLTYsIDYsIDEpLCBhc3BlY3QgPSAiZmlsbCIsCiAgeGxhYiA9ICIiLCB5bGFiID0gIiIsIHNjYWxlcyA9IGxpc3QoeCA9IGxpc3QoZHJhdyA9IEZBTFNFKSksCiAgcGFuZWwgPSBmdW5jdGlvbih4LCB5LCB6LCAuLi4pIHsKICAgIHBhbmVsLmxldmVscGxvdCh4LCB5LCB6LCAuLi4pCiAgICBwYW5lbC5hYmxpbmUoaCA9IDE6NSswLjUsIGNvbCA9ICJ3aGl0ZSIsIGx3ZCA9IDEuNSkKICB9CikKCnByaW50KHBsb3RfaGVhdG1hcCkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQojIHNpbGVudGx5IGV4cG9ydCBkZW5kcm9ncmFtCnBuZygiLi4vZmlndXJlcy9maWd1cmVfYmFyc2VxX2hlYXQucG5nIiwgd2lkdGggPSAxNjkwLCBoZWlnaHQgPSA0MDAsIHJlcyA9IDE1MCkKcHJpbnQocGxvdF9oZWF0bWFwKQpkZXYub2ZmKCkKYGBgCgpDbHVzdGVyaW5nIGFuZCBzaWxob3VldHRlIGFuYWx5c2lzIHJldmVhbGVkIHRoYXQgd2UgaGF2ZSA0IHRvIDcgY2x1c3RlcnMgd2l0aCBhY2NlcHRhYmxlIHNlcGFyYXRpb24sIHNlZSB0aGUgcGxvdCBiZWxvdy4gT2YgdGhlc2UsIHNldmVyYWwgY2x1c3RlcnMgc3RpY2sgb3V0OgoKMS4gbXV0YW50cyBzcGVjaWZpY2FsbHkgZGVwbGV0ZWQgaW4gZm9ybWF0ZSBjb25kaXRpb25zID0gZXNzZW50aWFsIGZvciBmb3JtYXRlCjIuIG11dGFudHMgZGVwbGV0ZWQgaW4gYWxsIGNvbmRpdGlvbnMgPSBlc3NlbnRpYWwgaW4gbWluaW1hbCBtZWRpdW0KMy4gbXV0YW50cyBlbnJpY2hlZCBpbiBmcnVjdG9zZSBncm93dGgsIG5ldXRyYWwgb24gb3RoZXIgc3Vic3RyYXRlcwo0LiBtdXRhbnRzIGVucmljaGVkIGluIGNvbnRpbnVvdXMgcmVnaW1lLCBtb3N0bHkgbmV1dHJhbCBpbiBwdWxzZWQgcmVnaW1lCjUuIG11dGFudHMgX3NsaWdodGx5XyBkZXBsZXRlZCBpbiBjb250aW51b3VzIHN1Y2NpbmF0ZSAtIGxvdyBwcmlvcml0eQo2LiBtdXRhbnRzIF9zbGlnaHRseV8gZGVwbGV0ZWQgaW4gY29udGludW91cyBmcnVjdG9zZSAtIGxvdyBwcmlvcml0eQo3LiBtdXRhbnRzIF9zbGlnaHRseV8gZGVwbGV0ZWQgaW4gdmFyaW91cyBjb25kaXRpb25zIC0gbG93IHByaW9yaXR5CgpgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA0fQpzaWxob3VldHRlUmVzdWx0IDwtIFJ0b29sczo6c2lsaG91ZXR0ZV9hbmFseXNpcyhtYXRfaGVhdG1hcCwgbWF0X2NsdXN0ZXIsIDI6MjApCnNpbGhvdWV0dGVSZXN1bHQkcGxvdC5zdW1tYXJ5CgojIHBsb3QgY29sb3JlZCBkZW5kcm9ncmFtCnBsb3QoY29sb3JfYnJhbmNoZXMoCiAgbWF0X2NsdXN0ZXIsIGsgPSA3LAogIGdyb3VwTGFiZWxzID0gVFJVRSwKICBjb2wgPSBzdGRjb2xbMTo3XQopKQoKIyBjb2xsZWN0IG5hbWVzIG9mIGVucmljaGVkL2RlcGxldGVkIGdlbmVzCmxpc3RfZW5yaWNoZWQgPC0gdmVnYW46OmN1dHJlZW9yZChtYXRfY2x1c3RlciwgayA9IDcpCmxpc3RfZW5yaWNoZWQgJT4lIHRhYmxlCmBgYAoKYGBge3IsIGluY2x1ZGUgPSBGQUxTRX0KIyBzaWxlbnRseSBleHBvcnQgZGVuZHJvZ3JhbQpwbmcoIi4uL2ZpZ3VyZXMvZmlndXJlX2JhcnNlcV9kZW5kcm8ucG5nIiwgd2lkdGggPSAxNjAwLCBoZWlnaHQgPSA3MDAsIHJlcyA9IDE1MCkKcGxvdChjb2xvcl9icmFuY2hlcygKICBtYXRfY2x1c3RlciwgayA9IDcsCiAgZ3JvdXBMYWJlbHMgPSBUUlVFLAogIGNvbCA9IHN0ZGNvbFsxOjddCikpCmRldi5vZmYoKQpgYGAKCgojIyMgRW5yaWNobWVudCBvZiBtdXRhbnRzIG92ZXIgdGltZSAoaW5jcmVhc2VkIGZpdG5lc3MpCgpPbmUgb2YgdGhlIG1vc3QgcHV6emxpbmcgcmVzdWx0cyBpcyB0aGUgYXBwZWFyYW5jZSBvZiAodmVyeSkgZmFzdCBncm93aW5nIG11dGFudHMgaW4gc29tZSBjb25kaXRpb25zLiBUaGVzZSBtdXRhbnRzIHF1aWNrbHkgZW5yaWNoIG92ZXIgb25seSAxNiBnZW5lcmF0aW9ucyB0byBhIHZvbHVtZSBvZiB1cCB0byAyMCUgb2YgYWxsIGxpYnJhcnkgbXV0YW50cywgdGhleSAidGFrZSBvdmVyIHRoZSBjdWx0dXJlIi4gVGhpcyBwaGVub21lbm9uIHdhcyBub3Qgb2JzZXJ2ZWQgcHJldmlvdXNseSBpbiBleHBlcmltZW50cyB3aXRoIHRoZSAqU3luZWNob2N5c3Rpcyogc3AuIFBDQzY4MDMgQ1JJU1BSaSByZXByZXNzaW9uIGxpYnJhcnkgKFlhbyBldCBhbC4sIE5hdHVyZSBDb21tdW5pY2F0aW9ucywgMjAyMCkuIFRoZSBDUklTUFJpIGxpYnJhcnkgaXMgYmFzZWQgb24gdGhlIHNhbWUgcHJpbmNpcGxlIG9mIGRlcGxldGlvbiBhbmQgZW5yaWNobWVudCBvZiBtdXRhbnRzIGRlcGVuZGluZyBvbiB0aGUgYXNzb2NpYXRlZCBmaXRuZXNzLgoKYGBge3IsIGVjaG8gPSBGQUxTRX0KIyBjb2xvciB2ZWN0b3IgZm9yIGNvbmRpdGlvbnMKc3Vic19jb2wgPC0gYyhzdGRjb2xbMV0sIGxpZ2h0ZW4oc3RkY29sWzFdLCAwLjMpLCBzdGRjb2xbMl0sCiAgbGlnaHRlbihzdGRjb2xbMl0sIDAuMyksIHN0ZGNvbFszXSwgbGlnaHRlbihzdGRjb2xbM10sIDAuMykpCgojIGdlbmVyYWxpemVkIGZ1bmN0aW9uIGZvciBiYXJwbG90cwpiYXJjaGFydF9maXRuZXNzIDwtIGZ1bmN0aW9uKGRhdGEpIHsKICAjIHNvcnQgYnkgY3VtdWxhdGl2ZSBmaXRuZXNzCiAgZGF0YSAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnKSAlPiUgCiAgbXV0YXRlKHN1bV9maXRuZXNzID0gc3VtKE5vcm1fZmdfbWVkaWFuKSkgJT4lCiAgYXJyYW5nZShzdW1fZml0bmVzcykgJT4lCiAgbXV0YXRlKG5hbWUgPSBwYXN0ZTAobG9jdXNfdGFnLCAiIHwgIiwgZWdnTk9HX25hbWUsICIgfCAiLCAKICAgIHN1YnN0cihlZ2dOT0dfZGVzY3JpcHRpb24sIDEsIDQwKSkpICU+JQogIAogIGJhcmNoYXJ0KGZhY3RvcihuYW1lLCB1bmlxdWUobmFtZSkpIH4gTm9ybV9mZ19tZWRpYW4sIC4sCiAgICBncm91cCA9IHBhc3RlKFN1YnN0cmF0ZSwgQ29uZGl0aW9uKSwKICAgIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksCiAgICBjb2wgPSBzdWJzX2NvbCwgYm9yZGVyID0gIndoaXRlIiwgc3RhY2sgPSBUUlVFLAogICAgeGxhYiA9ICJjdW11bGF0aXZlIGZpdG5lc3MiLAogICAgc2NhbGVzID0gbGlzdCh5ID0gbGlzdChjZXggPSAwLjcpKSwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gLTEsIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwuYmFyY2hhcnQoeCwgeSwgLi4uKQogICAgICBwYW5lbC5rZXkoLi4uLCBwb2ludHMgPSBGQUxTRSwgY2V4ID0gMC42LCBjb3JuZXIgPSBjKDAuOTcsIDAuMDMpKQogICAgfQogICkKfQoKbGluZWNoYXJ0X2ZpdG5lc3MgPC0gZnVuY3Rpb24oZGF0YSkgewogIHh5cGxvdChOb3JtX2ZnX21lZGlhbiB+IFRpbWUgfCBsb2N1c190YWcsIGRhdGEsCiAgICBncm91cHMgPSBwYXN0ZShTdWJzdHJhdGUsIENvbmRpdGlvbiksIGFzLnRhYmxlID0gVFJVRSwKICAgIHBhci5zZXR0aW5ncyA9IGN1c3RvbS5jb2xvcmJsaW5kKCksIHR5cGUgPSBjKCJsIiksCiAgICBjb2wgPSBzdWJzX2NvbCwgbHdkID0gMi41LAogICAgbGF5b3V0ID0gYyg1LCBjZWlsaW5nKGxlbmd0aCh1bmlxdWUoZGF0YSRsb2N1c190YWcpKS81KSksCiAgICB4bGFiID0gImdlbmVyYXRpb25zIiwgeWxhYiA9ICJmaXRuZXNzIiwKICAgIGJldHdlZW4gPSBsaXN0KHggPSAwLjUsIHkgPSAwLjUpLAogICAgc2NhbGVzID0gbGlzdChhbHRlcm5hdGluZyA9IEZBTFNFKSwKICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSB7CiAgICAgIHBhbmVsLmdyaWQoaCA9IC0xLCB2ID0gLTEsIGNvbCA9IGdyZXkoMC45KSkKICAgICAgcGFuZWwueHlwbG90KHgsIHksIC4uLikKICAgIH0KICApCn0KYGBgCgojIyMjIFN0cmFpbnMgZW5yaWNoZWQgb24gZnJ1Y3Rvc2UKCldoYXQgaXMgdGhlIGlkZW50aXR5IG9mIHRoZSBlbnJpY2hlZCBnZW5lcz8gV2hpY2ggb25lcyBhcmUgZW5yaWNoZWQgaW4gc2V2ZXJhbCBjb25kaXRpb25zPyBGaXJzdCB3ZSBpZGVudGlmeSB0aGUgbXV0YW50cyBoaWdobHkgYW5kIHNwZWNpZmljYWxseSBlbnJpY2hlZCBvbiBmcnVjdG9zZSwgcHJlZG9taW5hbnRseSBpbiB0aGUgY29udGludW91cyBncm93dGggcmVnaW1lLgoKCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDQuNX0KZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcihsb2N1c190YWcgJWluJSBuYW1lcyhzdWJzZXQobGlzdF9lbnJpY2hlZCwgbGlzdF9lbnJpY2hlZCA9PSAzKSkpICU+JQogIGZpbHRlcihUaW1lID09IDE2KSAlPiUKICBiYXJjaGFydF9maXRuZXNzKCkgJT4lCiAgcHJpbnQocG9zaXRpb24gPSBjKDAsMCwwLjYsMSksIG1vcmUgPSBUUlVFKQoKZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcihsb2N1c190YWcgJWluJSBuYW1lcyhzdWJzZXQobGlzdF9lbnJpY2hlZCwgbGlzdF9lbnJpY2hlZCA9PSAzKSkpICU+JQogIGxpbmVjaGFydF9maXRuZXNzKCkgJT4lCiAgcHJpbnQocG9zaXRpb24gPSBjKDAuNTgsMCwxLDEpKQpgYGAKCioqTWVjaGFuaXNtcyBlbmFibGluZyBmYXN0ZXIgZ3Jvd3RoIG9uIGZydWN0b3NlKioKClRoZSBtZWNoYW5pc20gZm9yIGluY3JlYXNlZCBncm93dGggb24gZnJ1Y3Rvc2Ugc2VlbXMgY2xlYXJseSBkaWZmZXJlbnQgZnJvbSB0aGUgbWVjaGFuaXNtIGZvciBmYXN0ZXIgZ3Jvd3RoIGluIGFsbCBvdGhlciAobWFpbmx5IGNvbnRpbnVvdXMpICBjb25kaXRpb25zLiBGb3IgdGhlIGZydWN0b3NlIHNldCwgc2V2ZXJhbCBnZW5lcyBhcmUgZnVuY3Rpb25hbGx5IGxpbmtlZCBzdWdnZXN0aW5nIGEgc2ltaWxhciBtZWNoYW5pc20gb2YgYWN0aW9uLCAKCjEuIEdlbmVzIGBIMTZfQjA1MTdgIChhbGNvaG9sIGRlaHlkcm9nZW5hc2UpIGFuZCBgSDE2X0IxOTE3YCAoYWxkZWh5ZGUgZGVoeWRyb2dlbmFzZSk6IEFjY29yZGluZyB0byBTVFJJTkcgREIsIHRoZSBnZW5lcyBhcmUgY28tbG9jYXRlZCBpLmUuIGVpdGhlciBpbiBkaXJlY3QgcHJveGltaXR5IG9yIGluIHRoZSBzYW1lIG9wZXJvbiBpbiBhbHBoYS0sIGJldGEtIGFuZCBnYW1tYS1wcm90ZW9iYWN0ZXJpYSwgYW5kIGV2ZW4gY3lhbm9iY2F0ZXJpYS4gQmlvQ3ljIGhhcyAxNyBwb3NzaWJsZSBpc28tZW56eW1lcyBpbiAqQ3VwcmlhdmlkdXMqIGZvciB0aGUgMi1lbnp5bWUgcGF0aHdheSAiZXRoYW5vbCBkZWdyYWRhdGlvbiAxIjogZXRoYW5vbCAtLT4gYWNldGFsZGVoeWRlIC0tPiBhY2V0eWwtQ29BIChyZXZlcnNlIEV0T0ggZmVybWVudGF0aW9uLCBvYnRhaW4gMSBOQURIIHBlciByZWFjdGlvbikgY2F0YWx5emVkIGJ5IGJvdGggZ2VuZXMuIFdoYXQgY291bGQgYmUgdGhlIG1lY2hhbmlzbSBmb3IgaW1wcm92ZWQgZ3Jvd3RoL3lpZWxkIG9uIGZydWN0b3NlPyBDaGVtb3N0YXRzIGFyZSBtb3JlIHlpZWxkLSB0aGFuIGdyb3d0aCBzZWxlY3RpdmUsIHRoaXMgcGF0aHdheSBpcyBwcm9iYWJseSBmdW5jdGlvbmFsIGFuZCBzZWNyZXRlcyBFdE9IIGFzIGEgZmVybWVudGF0aW9uIHByb2R1Y3Q7IEtPIG9mIHRoaXMgcGF0aHdheSBwcm9iYWJseSBpbmNyZWFzZXMgeWllbGQuCgoyLiBUd28gZ2VuZXMgYXJlIGludm9sdmVkIGluIG5pdHJhdGUgcmVzcGlyYXRpb24vcmVkdWN0aW9uLCBgUEhHMjY5YCBvciBuYXJLLCBhbmQgYEgxNl9CMjA4N2AsIGEgTmFyTC1mYW1pbHkgcmVzcG9uc2UgcmVndWxhdG9yLiBOYXJLIGlzIGEgbml0cmF0ZSB0cmFuc3BvcnRlciwgYW5kIE5hckwgc2Vuc2VzIG5pdHJhdGUgYW5kIHRoZW4gYWN0aXZhdGVzIHRyYW5zY3JpcHRpb24gb2YgaXRzIHRhcmdldHMgYnkgYmluZGluZyB0aGUgRE5BLiBBY2NvcmRpbmcgdG8gW3RoaXMgcGFwZXIgb24gTmFyTCBieSBSdWFudG8gZXQgYWwuLCAyMDIwXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM3NDE5MDc5LyksICJ0aGUgUmVndWxvbiBEQiBkYXRhYmFzZSBbMTFdIGZvciB0cmFuc2NyaXB0aW9uIHJlZ3VsYXRpb24gaW4gRS4gY29saSBsaXN0cyAyNiBnZW5lIHJlZ3VsYXRvcnkgcmVnaW9ucyB3aGVyZSBOYXJMIGhhcyBhIGRpcmVjdCBlZmZlY3Qgb24gdHJhbnNjcmlwdCBpbml0aWF0aW9uLCBhbmQgaXQgZnVuY3Rpb25zIGFzIGFuIGFjdGl2YXRvciBhdCAxMSBvZiB0aGVzZSIuIEl0IGlzIG5vdCBjbGVhciB3aGF0IGVmZmVjdCB0aGUgS08gb2Ygbml0cmF0ZSB0cmFuc3BvcnQgY291bGQgaGF2ZSBvbiBncm93dGggb3IgeWllbGQsIG5pdHJhdGUgaXMgbm90IHBhcnQgb2YgdGhlIG1lZGl1bS4KCjMuIEdlbmVzIGludm9sdmVkIGluIHRyYW5zbGF0aW9uL3Byb3RlaW4gZm9sZGluZy9zdWxwaHVyIG1ldGFib2xpc206CiAgICAtIGBIMTZfQjI1MjFgLCBBbHBoYS1rZXRvZ2x1dGFyYXRlLWRlcGVuZGVudCB0YXVyaW5lIGRpb3h5Z2VuYXNlOyB0YXVyaW5lIGlzIGEgc3VscGh1ciBjYXJyaWVyCiAgICAtIGBIMTZfQTI4NjFgLCBHbHV0YXRoaW9uZSBTLXRyYW5zZmVyYXNlOyBQb3N0dHJhbnNsYXRpb25hbCBtb2RpZmljYXRpb24sIHByb3RlaW4gdHVybm92ZXIsIGNoYXBlcm9uZXMKICAgIC0gYEgxNl9BMTEzOGAsIFRoaW9yZWRveGluOyBQb3N0dHJhbnNsYXRpb25hbCBtb2RpZmljYXRpb24sIHByb3RlaW4gdHVybm92ZXIsIGNoYXBlcm9uZXMKICAgIC0gYEgxNl9BMTMzNmAsIHlvZ0EvdGRjRiwgcHV0YXRpdmUgdHJhbnNsYXRpb24gaW5pdGlhdGlvbiBpbmhpYml0b3IseWpnIEZmYW1pbHk7IFRyYW5zbGF0aW9uLCByaWJvc29tYWwgc3RydWN0dXJlIGFuZCBiaW9nZW5lc2lzCiAgICAtIGBIMTZfQTI1NTNgLCBjTywgRE5BIHJlcGFpciBwcm90ZWluIFJlY087IEludm9sdmVkIGluIEROQSByZXBhaXIgYW5kIFJlY0YgcGF0aHdheSByZWNvbWJpbmF0aW9uCgo0LiBTZXZlcmFsIG90aGVyIGdlbmUgcHJvZHVjdHMgYXJlIHByZXN1bWFibHkgcmVndWxhdG9yeSBwcm90ZWluczoKICAgIC0gYDE2X0EwMzEwYCwgdHJhbnNjcmlwdGlvbmFsIHJlZ3VsYXRvciwgR250Ui1mYW1pbHk7IFRyYW5zY3JpcHRpb24KICAgIC0gYEgxNl9CMjIxNWAsIEhUSCBseXNSLXR5cGUgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpbjsgaGVsaXggdHVybiBoZWxpeCBETkEgYmluZGluZyBtb3RpZgoKIyMjIyBTdHJhaW5zIGVucmljaGVkIG9uIGZvcm1hdGUKCkhlcmUsIHRoZSBvYnZpb3VzIHF1ZXN0aW9uIHdpdGggYmlvdGVjaG5vbG9naWNhbCBpbXBvcnRhbmNlIGlzIHRvIGZpbmQgbXV0YW50cyB3aXRoIGhpZ2hlciAoc3BlY2lmaWMpIHRvbGVyYW5jZSB0byBmb3JtYXRlLCByZWdhcmRsZXNzIGlmIGl0J3MgcHVsc2VkIG9yIGNvbnRpbnVvdXNseSBzdXBwbGllZC4gV2UgZXhwbGljaXRseSBleGNsdWRlIG11dGFudHMgYmVuZWZpY2lhbCBmb3Igb3RoZXIgZ3Jvd3RoIGNvbmRpdGlvbnMgdG9vLCB3aGljaCBhcmUgZGVhbHQgd2l0aCBpbiB0aGUgbmV4dCBzZWN0aW9uLiBUaGUgY2x1c3RlcmluZyByZXN1bHRzIG9mIHRoZSBwcmV2aW91cyBzZWN0aW9uIGNvdWxkIG5vdCBpZGVudGlmeSBmb3JtYXRlLXNwZWNpZmljIG11dGFudHMgZW5yaWNoZWQgYWZ0ZXIgOCBnZW5lcmF0aW9ucy4gV2UgbmVlZCB0byBsb3dlciB0aGUgZmlsdGVyIHRocmVzaG9sZCB0byBkZXRlY3QgZ2VuZXMgdGhhdCBoYXZlIGEgbW9yZSBzdWJ0bGUgZW5yaWNobWVudCAoZml0bmVzcyA+PSAyIGZvciBmb3JtYXRlLCBhbmQgPD0gMSBmb3IgYWxsIG90aGVyIGNvbmRpdGlvbnMpIGFmdGVyIDE2IGdlbmVyYXRpb25zLgoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNC41fQpsaXN0X2ZpdG5lc3NfZm9ybWF0ZSA8LSBkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgZ3JvdXBfYnkobG9jdXNfdGFnLCBTdWJzdHJhdGUsIFRpbWUpICU+JQogIG11dGF0ZShmb3JtYXRlX2hpdCA9IGNhc2Vfd2hlbigKICAgIFN1YnN0cmF0ZSA9PSAiZm9ybWF0ZSIgJiBtYXgoTm9ybV9mZ19tZWRpYW4pID49IDIgfiBUUlVFLAogICAgU3Vic3RyYXRlICE9ICJmb3JtYXRlIiAmIG1heChOb3JtX2ZnX21lZGlhbikgPD0gMSB+IFRSVUUsCiAgICBUUlVFIH4gRkFMU0UpCiAgKSAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnLCBUaW1lKSAlPiUKICBmaWx0ZXIoYWxsKGZvcm1hdGVfaGl0KSwgbigpID09IDYpICU+JSAKICBwdWxsKGxvY3VzX3RhZykgJT4lIHVuaXF1ZQoKZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcihUaW1lID09IDE2LCBsb2N1c190YWcgJWluJSBsaXN0X2ZpdG5lc3NfZm9ybWF0ZSkgJT4lCiAgYmFyY2hhcnRfZml0bmVzcygpICU+JQogIHByaW50KHBvc2l0aW9uID0gYygwLDAsMC42LDEpLCBtb3JlID0gVFJVRSkKCmRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUKICBmaWx0ZXIobG9jdXNfdGFnICVpbiUgbGlzdF9maXRuZXNzX2Zvcm1hdGUpICU+JQogIGxpbmVjaGFydF9maXRuZXNzKCkgJT4lCiAgcHJpbnQocG9zaXRpb24gPSBjKDAuNTgsMCwxLDEpKQpgYGAKCioqTWVjaGFuaXNtcyBlbmFibGluZyBmYXN0ZXIgZ3Jvd3RoIG9uIGZvcm1hdGUqKgoKQWNjb3JkaW5nIHRvIFNUUklORyBEQiB0aGVyZSBhcmUgbm8gb2J2aW91cyByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlc2UgZ2VuZXMgZXhjZXB0IGZvciB0aGUgcGFpciBgUEhHMzg4YCAocGNhSSwgT3hvYWRpcGF0ZSBDb0EgdHJhbnNmZXJhc2UgYWxwaGEgc3VidW5pdCkgYW5kIGBIMTZfQjE1ODNgIChwY2FELCAzLU94b2FkaXBhdGUgZW5vbC1sYWN0b25lIGh5ZHJvbGFzZSkuIEJvdGggZ2VuZXMgYXJlIHBhcnQgb2YgdGhlIGNhdGVjaG9sIGRlZ3JhZGF0aW9uIHBhdGh3YXkgdGhhdCBpcyBpdHNlbGYgYSBsYXJnZXIgcGFydCBvZiBiZW56ZW5lIGRlZ3JhZGF0aW9uLiBUaGUgZ2VuZSBwcm9kdWN0cyBjYXRhbHl6ZSB0d28gc2VxdWVudGlhbCByZWFjdGlvbnMgMy1veG9hZGlwYXRlLWVub2wtbGFjdG9uZSAtLT4gMy1veG9hZGlwYXRlIChwY2FEKSAtLT4gMy1veG9hZGlweWwtQ29BIChwY2FJKS4gVGhlIG5leHQgcmVhY3Rpb24gY2F0YWx5emVkIGJ5IGZvdXIgaXNvZW56eW1lcyBtYWtlcyBzdWNjaW55bC1Db0Egd2hpY2ggZW5kcyB1cCBpbiB0aGUgQ2l0cmF0ZSBjeWNsZS4gSG93IHRoZSBLTyBvZiB0aGlzIHBhdGh3YXkgd291bGQgaW1wcm92ZSB0b2xlcmFuY2UgdG8gZm9ybWF0ZSBpcyB1bmNsZWFyLgoKIyMjIyBTdHJhaW5zIGVucmljaGVkIG9uIHN1Y2NpbmF0ZQoKVGhpcyBpcyBzaW1pbGFyIHRvIHRoZSBhbmFseXNpcyBhYm92ZSBmb3IgZm9ybWF0ZSwgd2l0aCB0aGUgZXhjZXB0aW9uIHRoYXQgbWFueSBtdXRhbnRzIGFzc29jaWF0ZWQgd2l0aCBoaWdoZXIgZml0bmVzcyBpbiBzdWNjaW5hdGUgY29uZGl0aW9ucyBlbnJpY2ggb25seSBhZnRlciAxNiBnZW5lcmF0aW9ucywgYW5kIG9ubHkgaW4gdGhlIGNvbnRpbnVvdXMgcmVnaW1lLiBUaGlzIHNlZW1zIGJlIGFuIGFydGlmYWN0IG9mIHJlYWQgY29tcHJlc3Npb24uIFdlIHRoZXJlZm9yZSB1c2UgdGhlIHNhbWUgdGhyZXNob2xkcyBhcyBmb3IgZm9ybWF0ZSAoZml0bmVzcyA+PSAyIGZvciBzdWNjaW5hdGUsIGFuZCA8PSAxIGZvciBhbGwgb3RoZXIgY29uZGl0aW9ucykgYnV0IGFmdGVyIDggaW5zdGVhZCBvZiAxNiBnZW5lcmF0aW9ucy4KCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDQuNX0KbGlzdF9maXRuZXNzX3N1Y2NpbmF0ZSA8LSBkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgZmlsdGVyKFRpbWUgPT0gOCkgJT4lCiAgZ3JvdXBfYnkobG9jdXNfdGFnLCBTdWJzdHJhdGUpICU+JQogIG11dGF0ZShzdWNjaW5hdGVfaGl0ID0gY2FzZV93aGVuKAogICAgU3Vic3RyYXRlID09ICJzdWNjaW5hdGUiICYgbWF4KE5vcm1fZmdfbWVkaWFuKSA+PSAyIH4gVFJVRSwKICAgIFN1YnN0cmF0ZSAhPSAic3VjY2luYXRlIiAmIG1heChOb3JtX2ZnX21lZGlhbikgPD0gMSB+IFRSVUUsCiAgICBUUlVFIH4gRkFMU0UpCiAgKSAlPiUgZ3JvdXBfYnkobG9jdXNfdGFnKSAlPiUKICBmaWx0ZXIoYWxsKHN1Y2NpbmF0ZV9oaXQpLCBuKCkgPT0gNiwgbG9jdXNfdGFnICE9ICJIMTZfQTI5MTIiKSAlPiUgCiAgcHVsbChsb2N1c190YWcpICU+JSB1bmlxdWUKCmRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUKICBmaWx0ZXIoVGltZSA9PSAxNiwgbG9jdXNfdGFnICVpbiUgbGlzdF9maXRuZXNzX3N1Y2NpbmF0ZSkgJT4lCiAgYmFyY2hhcnRfZml0bmVzcygpICU+JQogIHByaW50KHBvc2l0aW9uID0gYygwLDAsMC42LDEpLCBtb3JlID0gVFJVRSkKCmRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUKICBmaWx0ZXIobG9jdXNfdGFnICVpbiUgbGlzdF9maXRuZXNzX3N1Y2NpbmF0ZSkgJT4lCiAgbGluZWNoYXJ0X2ZpdG5lc3MoKSAlPiUKICBwcmludChwb3NpdGlvbiA9IGMoMC41OCwwLDEsMSkpCmBgYAoKKipNZWNoYW5pc21zIGVuYWJsaW5nIGZhc3RlciBncm93dGggb24gc3VjY2luYXRlKioKCkEgZ3JvdXAgb2YgZml2ZSBoaWdobHkgcmVsYXRlZCBnZW5lcyBzaG93cyBzaWduaWZpY2FudCBlbnJpY2htZW50IGluIChjb250aW51b3VzKSBzdWNjaW5hdGU6IGBIMTZfMjA5NmAgKGRwcEExKSwgYEgxNl9BMjQwNmAgKGRwcEQyKSwgYEgxNl9BMjQwN2AgKGRwcEMyKSwgYEgxNl9BMjQwOGAgKGRwcEIyKSwgYW5kIGBIMTZfQTI0MDlgLCBkcHBBMi4gQWx0ZXJuYXRpdmUgbmFtZXMgYXJlIHllakFCQ0RFLiBBbGwgb2YgdGhlc2UgcHJvdGVpbnMgYXJlIHBhcnQgb2YgYW4gQUJDIHRyYW5zcG9ydGVyIG9mIHRoZSBQZXBUIGZhbWlseS4gUXVvdGUgZnJvbSBQRkFNIGFib3V0IHRoaXMgdHlwZSBvZiBwcm90ZWluL2RvbWFpbjogIkFsbCBjaGFyYWN0ZXJpc2VkIG1lbWJlcnMgYXBwZWFyIHRvIGJlIGludm9sdmVkIGluIHRoZSB0cmFuc3BvcnQgb2Ygb2xpZ29wZXB0aWRlcyBvciBkaXBlcHRpZGVzLiBTb21lIGFyZSBpbXBvcnRhbnQgZm9yIHNwb3J1bGF0aW9uIG9yIGFudGliaW90aWMgcmVzaXN0YW5jZS4gU29tZSBkaXBlcHRpZGUgdHJhbnNwb3J0ZXJzIGFsc28gYWN0IG9uIHRoZSBoZW1lIHByZWN1cnNvciBkZWx0YS1hbWlub2xldnVsaW5pYyBhY2lkLgpUaGUgZW5yaWNobWVudCBzZWVtcyB0byBiZSBoaWdobHkgcmVwcm9kdWNpYmxlOiBlYWNoIG9mIHRoZXNlIGdlbmVzIGhhcyA3IHRvIDE1IGRpZmZlcmVudCBpbnNlcnRpb24gbXV0YW50cywgYWxsIHNob3dpbmcgdGhlIHNhbWUgYXZlcmFnZSBwYXR0ZXJuLiBBdCBsZWFzdCB0d28gbW9yZSBnZW5lcyBhcmUgYWxzbyBpbnZvbHZlZCBpbiAoYW1pbm8gYWNpZD8pIHRyYW5zcG9ydCwgYEgxNl9BMzI4NGAgYW5kIGBIMTZfQTI1MjFgLiBUaGUgbGF0dGVyIG9uZSBpcyBhICJELWFtaW5vIGFjaWQgdHJhbnNmZXJhc2UgKEQtQUFUKSwgcmVxdWlyZWQgYnkgYmFjdGVyaWEgdG8gY2F0YWx5c2UgdGhlIHN5bnRoZXNpcyBvZiBELWdsdXRhbWljIGFjaWQgYW5kIEQtYWxhbmluZSIgKFBGQU0pLgpTdXBwb3NlZCBtZWNoYW5pc20gb2YgZW5yaWNobWVudDogR3Jvd3RoIG9uIHN1Y2NpbmF0ZSBjb3VsZCBsZWFkIHRvIGEgc2hvcnRhZ2UvaW1iYWxhbmNlIG9mIGNlcnRhaW4gYW1pbm8gYWNpZHMsIGFuZCBpbnZlc3RtZW50IGluIHVwdGFrZSBtaWdodCBnaXZlIGEgZ3Jvd3RoIGFkdmFudGFnZS4KCiMjIyMgU3RyYWlucyBlbnJpY2hlZCBpbiBzZXZlcmFsIGNvbmRpdGlvbnMKCkEgd2VhbHRoIG9mIGdlbmVzL211dGFudHMgYXJlIGVucmljaGVkIGluIG11bHRpcGxlIG1haW5seSBwdWxzZWQgZ3Jvd3RoIGNvbmRpdGlvbnMgKGNsdXN0ZXIgNCkuCgpgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA2LjV9CmRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUKICBmaWx0ZXIobG9jdXNfdGFnICVpbiUgbmFtZXMoc3Vic2V0KGxpc3RfZW5yaWNoZWQsIGxpc3RfZW5yaWNoZWQgPT0gNCkpKSAlPiUKICBmaWx0ZXIoVGltZSA9PSAxNikgJT4lCiAgYmFyY2hhcnRfZml0bmVzcygpICU+JQogIHByaW50KHBvc2l0aW9uID0gYygwLDAsMC42LDEpLCBtb3JlID0gVFJVRSkKCmRmX2ZpdG5lc3Nfc3VtbWFyeSAlPiUKICBmaWx0ZXIobG9jdXNfdGFnICVpbiUgbmFtZXMoc3Vic2V0KGxpc3RfZW5yaWNoZWQsIGxpc3RfZW5yaWNoZWQgPT0gNCkpKSAlPiUKICBsaW5lY2hhcnRfZml0bmVzcygpICU+JQogIHByaW50KHBvc2l0aW9uID0gYygwLjU4LDAsMSwxKSkKYGBgCgpUbyBsZWFybiBtb3JlIGFib3V0IGZ1bmN0aW9uYWwgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIGVucmljaGVkIGdlbmVzL211dGFudHMsIHdlIGNhbiBzdWJtaXQgdGhlIGdlbmUgbGlzdCB0byB0aGUgU1RSSU5HIGludGVyYWN0aW9uIGRhdGFiYXNlIGFuZCByZXRyaWV2ZSBhIG5ldHdvcmsgb2YgcHJvYmFibGUgaW50ZXJhY3Rpb25zLgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkodGlkeWdyYXBoKQoKIyBmdW5jdGlvbiByZXRyaWV2ZSBuZXR3b3JrIGludGVyYWN0aW9uIGRhdGEgZnJvbSBTVFJJTkcgREIKIyBzZXBhcmF0ZSBnZW5lIElEcyBieSAiJTBkIjsgc3BlY2llcy90YXhvbiBJRCBmb3IgQ3VwcmlhdmlkdXMgbmVjYXRvciBIMTY6IDM4MTY2NgojIChzZWUgaHR0cHM6Ly9zdHJpbmctZGIub3JnL2NnaS9vcmdhbmlzbXMpCnJldHJpZXZlX1NUUklORyA8LSBmdW5jdGlvbihnZW5lX0lELCB0YXhvbl9JRCwgbWluX3Njb3JlID0gMDAwMCwgcmVmID0gTlVMTCkgewogIGdlbmVfbGlzdCA8LSBwYXN0ZShnZW5lX0lELCBjb2xsYXBzZSA9ICIlMGQiKQogIHN0cmluZ19ncmFwaCA8LSBwYXN0ZTAoCiAgICAiaHR0cHM6Ly9zdHJpbmctZGIub3JnL2FwaS90c3YvbmV0d29yaz9pZGVudGlmaWVycz0iLCAKICAgIGdlbmVfbGlzdCwgIiZzcGVjaWVzPSIsIHRheG9uX0lELCAiJnJlcXVpcmVkX3Njb3JlPSIsIG1pbl9zY29yZSkgJT4lCiAgcmVhZF90c3YoY29sX3R5cGVzID0gY29scygpKSAlPiUKICBtdXRhdGUoYWNyb3NzKG1hdGNoZXMoInN0cmluZ0lkIiksIGZ1bmN0aW9uKHgpIGdzdWIocGFzdGUwKHRheG9uX0lELCAiLiIpLCAiIiwgeCkpKSAlPiUKICBhc190YmxfZ3JhcGgoKQogIGlmICghaXMubnVsbChyZWYpKSB7CiAgICBsZWZ0X2pvaW4oc3RyaW5nX2dyYXBoLCByZWYsIGJ5ID0gIm5hbWUiKQogIH0gZWxzZSB7CiAgICBzdHJpbmdfZ3JhcGgKICB9Cn0KYGBgCgoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA0Ljh9CmdyYXBoX2FsbF9lbnJpY2ggPC0gcmV0cmlldmVfU1RSSU5HKAogIGdlbmVfSUQgPSBuYW1lcyhzdWJzZXQobGlzdF9lbnJpY2hlZCwgbGlzdF9lbnJpY2hlZCA9PSA0KSksCiAgdGF4b25fSUQgPSAzODE2NjYsCiAgcmVmID0gcmVuYW1lKGRmX3JlZiwgbmFtZSA9IGxvY3VzX3RhZykKKQoKZ3JhcGhfYWxsX2VucmljaCAlPiUgYXJyYW5nZShDT0dfUHJvY2VzcykgJT4lIGFjdGl2YXRlKGVkZ2VzKSAlPiUgCiAgZmlsdGVyKHNjb3JlID49IDAuNCkgJT4lCiAgZ2dyYXBoKGxheW91dCA9ICdsaW5lYXInLCBjaXJjdWxhciA9IFRSVUUpICsKICBnZW9tX2VkZ2VfYXJjKGNvbG91ciA9IGdyZXkoMC42LCAwLjUpLCBhZXMod2lkdGggPSBzY29yZSkpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhjb2xvdXIgPSBDT0dfUHJvY2VzcyksIHNpemUgPSA1KSArCiAgZ2VvbV9ub2RlX3RleHQobnVkZ2VfeSA9IDAuMSwgc2l6ZSA9IDMuMiwgYWVzKGxhYmVsID0gZWdnTk9HX25hbWUsIGNvbG91ciA9IENPR19Qcm9jZXNzKSkgKwogIHNjYWxlX2VkZ2Vfd2lkdGgocmFuZ2UgPSBjKDAuMiwgMikpICsKICB0aGVtZV9ncmFwaChiYWNrZ3JvdW5kID0gIndoaXRlIiwgZm9yZWdyb3VuZCA9IGdyZXkoMC41KSwKICAgIHBsb3RfbWFyZ2luID0gbWFyZ2luKDEwLCAxMCwgMTAsIDEwKSkKYGBgCgoqKk1lY2hhbmlzbXMgZW5hYmxpbmcgZmFzdGVyIGdyb3d0aCBpbiBzZXZlcmFsIGNvbmRpdGlvbnMqKgoKVGhlIHBpY3R1cmUgZm9yIHRoZXNlIHN0cmFpbnMgaXMgbW9yZSBjbGVhciB0aGVuIGZvciB0aGUgZnJ1Y3Rvc2UtZW5yaWNoZWQgc3RyYWlucy4gMTMgb3V0IG9mIDI3IGVucmljaGVkIGdlbmVzICg0OCUpLCBhbW9uZyB0aGVtIHNvbWUgb2YgdGhlIG1vc3QgZW5yaWNoZWQsIGFyZSBkaXJlY3RseSBpbnZvbHZlZCBpbiBoeWRyb2dlbmFzZSBhY3Rpdml0eSwgaS5lLiBoeWRyb2dlbiBveHlnZW5hdGlvbiAoaG94QSwgaG94RiwgaG94VSwgaG94WCwgaHlwQSwgaHlwQiwgaHlwQywgaHlwRCBoeXBFLCBoeXBGLCBoeWFBLCBoeWFCLCBodXBIKS4gVGhlIG1lY2hhbmlzbSBvZiBlbmFibGluZyBmYXN0ZXIgZ3Jvd3RoIGJ5IEtPIG9mIGh5ZHJvZ2VuYXNlcyBpcyB1bmtub3duLgoKVGhlIHNlY29uZCB0aGVtZSBpcyBlbnJpY2htZW50IG9mIHB0c0kgKGBIMTZfQTAzMjZgKSBhbmQgcHRzSCAoYEgxNl9BMDMyNWApLCB0b2dldGhlciB0aGUgZW50aXJlIGZ1bmN0aW9uYWwgdW5pdCBvZiB0aGUgUFRTIHN5c3RlbSwgdGhlIFBFUC1kZXBlbmRlbnQgc3VnYXIgcGhvc3Bob3RyYW5zZmVyYXNlIHN5c3RlbSAoc3VnYXIgUFRTKS4gIlRoaXMgbWFqb3IgY2FyYm9oeWRyYXRlIGFjdGl2ZS10cmFuc3BvcnQgc3lzdGVtIGNhdGFseXplcyB0aGUgcGhvc3Bob3J5bGF0aW9uIG9mIGluY29taW5nIHN1Z2FyIHN1YnN0cmF0ZXMgY29uY29taXRhbnRseSB3aXRoIHRoZWlyIHRyYW5zbG9jYXRpb24gYWNyb3NzIHRoZSBjZWxsIG1lbWJyYW5lLiBFbnp5bWUgSSB0cmFuc2ZlcnMgdGhlIHBob3NwaG9yeWwgZ3JvdXAgZnJvbSAoUEVQKSB0byB0aGUgcGhvc3Bob3J5bCBjYXJyaWVyIHByb3RlaW4gKEhQcikuIgpXaHkgZG9lcyB0aGUgS08gb2YgUFRTIHN5c3RlbSBwcm92aWRlcyBhIGdyb3d0aCBiZW5lZml0IGluICppbiBhbGwgY29uZGl0aW9ucyogd2l0aCBhbG1vc3QgZXF1YWwgY29udHJpYnV0aW9uPyBNdXN0IGJlIHJlbGF0ZWQgdG8gZW5lcmd5IG1ldGFib2xpc20sIGJlY2F1c2UgbmVpdGhlciBmcnVjdG9zZSAoQUJDIHRyYW5zcG9ydGVyKSwgc3VjY2luYXRlIGFuZCBkZWYgbm90IGZvcm1hdGUgYXJlIHRyYW5zcG9ydGVkIHZpYSBhIFBUUy4KCk90aGVyIGludGVyZXN0aW5nIG1lY2hhbmlzbXM6IEtPIG9mIFJOQSBwb2x5bWVyYXNlIHNpZ21hIGZhY3RvciBScG9TIChgSDE2X0EyMzczYCkgc2VlbXMgdG8gaGF2ZSBhIGJlbmVmaWNpYWwgZWZmZWN0IG9uIHN0ZWFkeSBzdGF0ZSBncm93dGgsIGFzIHdlbGwgYXMgb3RoZXIgc3RyZXNzIHJlbGF0ZWQgdHJhbnNjcmlwdGlvbiBmYWN0b3JzIGxpa2UgY29sZCBzaG9jayBwcm90ZWluIGNhcEIgKGBIMTZfQjIyMDVgKSwgYW5kIHNjb0YgKGBIMTZfQjAwMDJgKS4KClRoZSBnZW5lIGBIMTZfQjIwNDNgIGlzIGJ5IGZhciBtb3N0IGFidW5kYW50IChieSByZWFkcykgYW5kIG1vc3QgZW5yaWNoZWQgKGJ5IGZpdG5lc3MpIHNpbmdsZSBtdXRhbnQgaW4gYWxtb3N0IGFsbCBjb25kaXRpb25zLiBXaGF0IGlzIHRoZSBtZWNoYW5pc20/IFRoZXJlIGlzIGFsbW9zdCBub3RoaW5nIGtub3duIGFib3V0IHRoaXMgZ2VuZSBleGNlcHQgdGhhdCBpdCBwcm9iYWJseSBoYXMgY3ljbGljLWd1YW55bGF0ZS1zcGVjaWZpYyBwaG9zcGhvZGllc3RlcmFzZSBhY3Rpdml0eS4gVGhpcyBlbnp5bWUgaGFzLCBhY2NvcmRpbmcgdG8gUEZBTSwgdHdvIGRvbWFpbnMsIHRoZSBkaWd1YW55bGF0ZSBjeWNsYXNlIChHR0RFRikgYW5kIHRoZSBFQUwgZG9tYWluLiBUaGUgZmlyc3Qgb25lIHN5bnRoZXNpemVzIGN5Y2xpYyBkaS1HTVAgW1J5amVua292IGV0IGFsLiwgSiBCYWN0LCAyMDA1XShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUMxMDY0MDE2LykuIFRoZSBzZWNvbmQgZG9tYWluIGNhbiBhY3QgYXMgcGhvc3Bob2RpZXN0ZXJhc2UgYW5kIGNsZWF2ZSBjeWNsaWMgY0FNUCBvciBjR01QLiBCb3RoIGNvbXBvdW5kcyBwbGF5IGEgcm9sZSBpbiBzaWduYWxpbmcsIGNBTVAgZm9yIGV4YW1wbGUgYXMgdGhlIGhvcm1vbmUgaW4gY2F0YWJvbGl0ZSByZXByZXNzaW9uLiBBY2NvcmRpbmcgdG8gdGhlIGRpc2N1c3Npb24gaW4gdGhlIGxpbmtlZCBwYXBlciwgIk11dGF0aW9ucyBpbiB0aGUgR0dERUYgZG9tYWluIHByb3RlaW5zIG9yIG92ZXJleHByZXNzaW9uIG9mIHN1Y2ggcHJvdGVpbnMgYWZmZWN0IGV4b3BvbHlzYWNjaGFyaWRlIHN5bnRoZXNpcyBbLi4uXSBhbmQgZm9ybWF0aW9uIG9mIGJpb2ZpbG1zLiBJbiBDLiBjcmVzY2VudHVzLCBmbGFnZWxsdW0gZWplY3Rpb24sIHdoaWNoIGlzIHJlcXVpcmVkIGZvciB0aGUgc3dpdGNoIGZyb20gbW90aWxlIHRvIHNlc3NpbGUgbGlmZXN0eWxlLCBpcyBpbXBhaXJlZCBpbiBhIG11dGF0ZWQgR0dERUYgZG9tYWluIi4gVGhlIHVuZGVybHlpbmcgbWVjaGFuaXNtIGNvdWxkIGJlIGRpc3J1cHRlZCBiaW9maWxtIGZvcm1hdGlvbiwgaGlnaGVyIGZsYWdlbGx1bSBhY3Rpdml0eSwgYW5kIHRodXMgbm9uLXNldHRsaW5nIHBoZW5vdHlwZSBpbiB0aGUgYmlvcmVhY3Rvci4gQWx0ZXJuYXRpdmVseSB0aGUgbXV0YXRpb24gYWZmZWN0cyBjQU1QIGZvcm1hdGlvbiBhbmQgZGlzcnVwdHMgb3IgZW5oYW5jZXMgY2F0YWJvbGl0ZSByZXByZXNzaW9uIChtb3JlIGxpa2VseSB0aGF0IGRpc3J1cHRlZCBjYXRhYm9saXRlIHJlcHJlc3Npb24gaXMgYmVuZWZpY2lhbCkuCgoKIyMjIyBTYW5pdHkgY2hlY2tzCgpBbGwgYWJvdmUgcmVzdWx0cyBhcmUgYmFzZWQgb24gZml0bmVzcyBzY29yZSwgd2hpY2ggaXMgbm90IG11Y2ggbW9yZSB0aGFuIGEgbm9ybWFsaXplZCBsb2cyIGZvbGQgY2hhbmdlIG9mIHJlYWQgY291bnQgb3ZlciB0aW1lLgpXZSBjYW4gY29tcGFyZSBpZiB0aGUgbXV0YW50cyB3aXRoIGV4dHJlbWVseSBoaWdoIGZpdG5lc3Mgc2NvcmVzIGFyZSBhbHNvIHRoZSBvbmVzIHRoYXQgYXJlIHN1cGVyLWFidW5kYW50IGF0IHRoZSBmaW5hbCB0aW1lIHBvaW50LCBpZS5lLiBoYXZlIGFuIGF2ZXJhZ2UgcmVhZCBjb3VudCBvZiA+PSA1MDAsMDAwIGFmdGVyIDE2IGdlbmVyYXRpb25zLiBJbiBmYWN0LCBvbmx5IDMgZ2VuZXMgaGF2ZSBzdWNoIGFuIGV4dHJlbWUgcmVhZCBjb3VudCwgYnV0IDkgaGF2ZSBtb3JlIHRoYW4gMTAwLDAwMCByZWFkcy4KCmBgYHtyfQpkZl9maXRuZXNzICU+JSBmaWx0ZXIoVGltZSA9PSAxNiwgbG9jdXNfdGFnICVpbiUgKHN1YnNldChsaXN0X2VucmljaGVkLCBsaXN0X2VucmljaGVkICVpbiUgYygzLDQpKSAlPiUgbmFtZXMpKSAlPiUKICBncm91cF9ieShsb2N1c190YWcpICU+JSBzdW1tYXJpemUobWF4X2NvdW50cyA9IG1heChDb3VudHMpLCBtYXhfZml0bmVzcyA9IG1heChOb3JtX2ZnKSkgJT4lCiAgYXJyYW5nZShkZXNjKG1heF9jb3VudHMpKQpgYGAKCk9uIHRoZSBvdGhlciBoYW5kLCB3ZSBjYW4gY2hlY2sgd2hpY2ggZ2VuZXMgaGF2ZSBhbiBleHRyZW1lbHkgaGlnaCByZWFkIGNvdW50ICg+PSA1MDAsMDAwIGluICphbnkqIGNvbmRpdGlvbikgYW5kIHNlZSBpZiB0aGlzIGNvcnJlbGF0ZXMgd2l0aCBoaWdoIGZpdG5lc3Mgc2NvcmUuIEl0IGRvZXMgcGFydGx5LiAzIG91dCBvZiA3IGhpZ2hseSBhYnVuZGFudCBnZW5lIG11dGFudHMgZW5yaWNoIGV4dHJlbWVseSBvdmVyIHRpbWUuIFRoZSBvdGhlciBlbnJpY2ggdG9vLCBidXQgb25seSAyXjEgPSAyIHRvIDJeMy41ID0gMTEgdGltZXMuIFRoZXNlIG5vbi1lbnJpY2hpbmcgc3VwZXItYWJ1bmRhbnQgbXV0YW50cyBhcmU6CgogIC0gYEgxNl9BMDc3NGAgLSBjcGhBLCBDeWFub3BoeWNpbiBzeW50aGFzZS4gU3VwcG9zZWQgbWVjaGFuaXNtOiBlbnJpY2hlcyBpbiBMQiBtZWRpdW0gYXMgaXQgZG9lcyBub3QgdHVybiBBc3AKICAgIGludG8gY3lhbm9waHljaW4uIE5vIGJlbmVmaXQgb24gbWluaW1hbCBtZWRpdW0uCiAgLSBgSDE2X0IyNTcwYCAtIGZlY0EsIE91dGVyIG1lbWJyYW5lIHJlY2VwdG9yIGZvciBGZShJSUkpLiBTdXBwb3NlZCBtZWNoYW5pc206IHJlZ3VsYXRvciBhY3Rpdml0eSB0b2dldGhlciB3aXRoIGZlY1IsIGJ1dCBhbHNvIAogICAgdHJhbnNtZW1icmFuZSB0cmFuc3BvcnRlciBmb3Igc2lkZXJvcGhvcmVzLiBLTyByZWR1Y2VzIHNlbnNpdGl2dHkgdG8gZXhjZXNzIGlyb24/PwogIC0gYEgxNl9BMzE0NWAgLSBDb25zZXJ2ZWQgcHJvdGVpbi9kb21haW4gdHlwaWNhbGx5IGFzc29jaWF0ZWQgd2l0aCBmbGF2b3Byb3RlaW4gb3h5Z2VuYXNlcywgRElNNi9OVEFCIGZhbWlseS4gCiAgICBTdXBwb3NlZCBtZWNoYW5pc206IHVua25vd24uCgpgYGB7cn0KZGZfZml0bmVzcyAlPiUgZmlsdGVyKFRpbWUgPT0gMTYsIENvdW50cyA+IDUqMTBeNSkgJT4lCiAgZ3JvdXBfYnkobG9jdXNfdGFnKSAlPiUgc3VtbWFyaXplKG1heF9jb3VudHMgPSBtYXgoQ291bnRzKSwgbWF4X2ZpdG5lc3MgPSBtYXgoTm9ybV9mZykpICU+JQogIGFycmFuZ2UoZGVzYyhtYXhfY291bnRzKSkKYGBgCgoKIyMjIERlcGxldGlvbiBvZiBtdXRhbnRzIG92ZXIgdGltZSAocmVkdWNlZCBmaXRuZXNzKQoKIyMjIyBEZXBsZXRpb24gb24gZm9ybWF0ZQoKU2V2ZXJhbCBnZW5lcy9tdXRhbnRzIGFyZSBkZXBsZXRlZCBvdmVyIHRpbWUgZGVwZW5kaW5nIG9uIGdyb3d0aCBjb25kaXRpb24uIE1vc3QgaW50ZXJlc3RpbmcgaW4gdGhpcyBjb250ZXh0IGFyZSBjbHVzdGVyIDEgYW5kIDIsIGRlcGxldGlvbiBvbmx5IG9uIGZvcm1hdGUsIG9yIGluIGFsbCBjb25kaXRpb25zLCByZXNwZWN0aXZlbHkuIE5vdCBzdXJwcmlzaW5nbHksIGZvcm1hdGUtc3BlY2lmaWMgZ2VuZXMgYXJlIGhpZ2hseSBkZXBsZXRlZCBkdXJpbmcgZ3Jvd3RoIG9uIGZvcm1hdGUsIGJ1dCBub3QgY2JiIChDYWx2aW4gY3ljbGUpIGdlbmVzLgoKCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDYuNX0KZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcihsb2N1c190YWcgJWluJSBuYW1lcyhzdWJzZXQobGlzdF9lbnJpY2hlZCwgbGlzdF9lbnJpY2hlZCA9PSAxKSkpICU+JQogIGZpbHRlcihUaW1lID09IDE2KSAlPiUKICBiYXJjaGFydF9maXRuZXNzKCkgJT4lCiAgcHJpbnQocG9zaXRpb24gPSBjKDAsMCwwLjYsMSksIG1vcmUgPSBUUlVFKQoKZGZfZml0bmVzc19zdW1tYXJ5ICU+JQogIGZpbHRlcihsb2N1c190YWcgJWluJSBuYW1lcyhzdWJzZXQobGlzdF9lbnJpY2hlZCwgbGlzdF9lbnJpY2hlZCA9PSAxKSkpICU+JQogIGxpbmVjaGFydF9maXRuZXNzKCkgJT4lCiAgcHJpbnQocG9zaXRpb24gPSBjKDAuNTgsMCwxLDEpKQpgYGAKCldoYXQgaXMgdGhlIHJvbGUgb2YgZm9ybWF0ZS1lc3NlbnRpYWwgZ2VuZXM/IEFyZSB0aGVyZSBwYXR0ZXJucyB0aGF0IGVtZXJnZT8gV2UgY2FuIHN1Ym1pdCB0aGUgZGVwbGV0ZWQgZ2VuZSBsaXN0IHRvIFNUUklORyBEQiBhbmQgcmV0cmlldmUgYSBwb3NzaWJsZSBuZXR3b3JrIG9mIGludGVyYWN0aW9ucy4gVGhlIG5ldHdvcmsgc2hvd3MgaW1tZWRpYXRlbHkgdGhhdCB0aGVyZSBhcmUgbWFueSBoaWdoLXNjb3JpbmcgaW50ZXJhY3Rpb25zIGJldHdlZW4gdGhlIGdlbmVzLCBwYXJ0aWN1bGFybHkgdGhlIHNvbHVibGUgRkRIIGdlbmVzIGFyZSBzdGlja2luZyBvdXQgYXMgb25lIGNsdXN0ZXIgKGZkc0FCREcpIGFuZCB0aGVpciB0cmFuc2NyaXB0aW9uYWwgcmVndWxhdG9yIGZkc1IuIFRoZW4gdGhlIG1vbHliZGVudW0gY29mYWN0b3IgcHJvY2Vzc2luZyBwcm90ZWlucyBtb2FDREUsIG1vZUEsIG1vYkEsIG1vZy4gQW5kIGEgcmFuZ2Ugb2YgY3l0b2Nocm9tZSBnZW5lcyByZXNwb25zaWJsZSBmb3IgYWNjZXB0YW5jZSBhbmQgdHJhbnNwb3J0IG9mIG9mIGVsZWN0cm9ucyBmcm9tIGZvcm1hdGUgdG8gdGhlIEVUQyBpbiBjeXRvcGxhc21pYyBtZW1icmFuZSAocGV0QUJDLCBjY29HTk9QLCBjeWMpLiBJdCBpcyBhbHNvIGludGVyc3Rpbmcgd2hhdCBpcyBOT1QgZXNzZW50aWFsIG9uIGZvcm1hdGUsIHN1Y2ggYXMgbm8gY2JiIGdlbmVzIGV4Y2VwdCB0aGUgbWFzdGVyIHRyYW5zY3JpcHRpb25hbCByZWd1bGF0b3IgY2JiUi4gVGhlIHJlYXNvbiBmb3IgdGhpcyBtdXN0IGJlIHRoZSByZWR1bmRhbmN5IG9mIGFsbCBjYmIgZ2VuZXMgKHR3byBvcGVyb25zKS4KCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDQuOH0KZ3JhcGhfZm9ybWF0ZV9kZXBsIDwtIHJldHJpZXZlX1NUUklORygKICBnZW5lX0lEID0gbmFtZXMoc3Vic2V0KGxpc3RfZW5yaWNoZWQsIGxpc3RfZW5yaWNoZWQgPT0gMSkpLAogIHRheG9uX0lEID0gMzgxNjY2LAogIHJlZiA9IHJlbmFtZShkZl9yZWYsIG5hbWUgPSBsb2N1c190YWcpCikKCmdyYXBoX2Zvcm1hdGVfZGVwbCAlPiUgYXJyYW5nZShDT0dfUHJvY2VzcykgJT4lIGFjdGl2YXRlKGVkZ2VzKSAlPiUgCiAgZmlsdGVyKHNjb3JlID49IDAuNCkgJT4lCiAgZ2dyYXBoKGxheW91dCA9ICdsaW5lYXInLCBjaXJjdWxhciA9IFRSVUUpICsKICBnZW9tX2VkZ2VfYXJjKGNvbG91ciA9IGdyZXkoMC42LCAwLjUpLCBhZXMod2lkdGggPSBzY29yZSkpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhjb2xvdXIgPSBDT0dfUHJvY2VzcyksIHNpemUgPSA1KSArCiAgZ2VvbV9ub2RlX3RleHQobnVkZ2VfeSA9IDAuMSwgc2l6ZSA9IDMuMiwgYWVzKGxhYmVsID0gZWdnTk9HX25hbWUsIGNvbG91ciA9IENPR19Qcm9jZXNzKSkgKwogIHNjYWxlX2VkZ2Vfd2lkdGgocmFuZ2UgPSBjKDAuMiwgMikpICsKICB0aGVtZV9ncmFwaChiYWNrZ3JvdW5kID0gIndoaXRlIiwgZm9yZWdyb3VuZCA9IGdyZXkoMC41KSwKICAgIHBsb3RfbWFyZ2luID0gbWFyZ2luKDEwLCAxMCwgMTAsIDEwKSkKYGBgCgoKIyMjIyBEZXBsZXRpb24gaW4gYWxsIGNvbmRpdGlvbnMKCldoaWNoIGdlbmVzIGFyZSBkZXBsZXRlZCBpbiBhbGwgY29uZGl0aW9ucyAoY2x1c3RlciAyKT8gSGVyZSB3ZSBzZWUgdGhlIGVmZmVjdCBvZiB0aGUgcmVhZCBjb21wcmVzc2lvbiwgc3VjaCB0aGF0IG1hbnkgZ2VuZXMgc2VlbSB0byAicmVjb3ZlciIgZnJvbSBpbml0aWFsIGRlcGxldGlvbiBhbmQgZW5yaWNoIGZyb20gOCB0byAxNiBnZW5lcmF0aW9uIHRpbWUgcG9pbnQuIFRoaXMgZWZmZWN0IGlzIG9ubHkgYXBwYXJlbnQgZm9yIHRoZSBjb250aW51b3VzIGNvbmRpdGlvbnMgYW5kIHdpdGggdmVyeSBoaWdoIHByb2JhYmlsaXR5IHJlbGF0ZWQgdG8gdGhlIGRpc3RvcnRpb24gb2YgcmVhZCBjb3VudHMgYnkgc3VwZXItZW5yaWNoaW5nIG11dGFudHMuIFRoZSA4IGdlbmVyYXRpb24gdGltZSBwb2ludCBzaG91bGQgYmUgY29uc2lkZXJlZCBhcyBtb3JlIHJlbGlhYmxlIGluIHRob3NlIGNhc2VzLgoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNi41fQpkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgZmlsdGVyKGxvY3VzX3RhZyAlaW4lIG5hbWVzKHN1YnNldChsaXN0X2VucmljaGVkLCBsaXN0X2VucmljaGVkID09IDIpKSkgJT4lCiAgZmlsdGVyKFRpbWUgPT0gMTYpICU+JQogIGJhcmNoYXJ0X2ZpdG5lc3MoKSAlPiUKICBwcmludChwb3NpdGlvbiA9IGMoMCwwLDAuNiwxKSwgbW9yZSA9IFRSVUUpCgpkZl9maXRuZXNzX3N1bW1hcnkgJT4lCiAgZmlsdGVyKGxvY3VzX3RhZyAlaW4lIG5hbWVzKHN1YnNldChsaXN0X2VucmljaGVkLCBsaXN0X2VucmljaGVkID09IDIpKSkgJT4lCiAgbGluZWNoYXJ0X2ZpdG5lc3MoKSAlPiUKICBwcmludChwb3NpdGlvbiA9IGMoMC41OCwwLDEsMSkpCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA1LjJ9CmdyYXBoX2FsbF9kZXBsIDwtIHJldHJpZXZlX1NUUklORygKICBnZW5lX0lEID0gbmFtZXMoc3Vic2V0KGxpc3RfZW5yaWNoZWQsIGxpc3RfZW5yaWNoZWQgPT0gMikpLAogIHRheG9uX0lEID0gMzgxNjY2LAogIHJlZiA9IHJlbmFtZShkZl9yZWYsIG5hbWUgPSBsb2N1c190YWcpCikKCmdyYXBoX2FsbF9kZXBsICU+JSBhcnJhbmdlKENPR19Qcm9jZXNzKSAlPiUgYWN0aXZhdGUoZWRnZXMpICU+JSAKICBmaWx0ZXIoc2NvcmUgPj0gMC40KSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gJ2xpbmVhcicsIGNpcmN1bGFyID0gVFJVRSkgKwogIGdlb21fZWRnZV9hcmMoY29sb3VyID0gZ3JleSgwLjYsIDAuNSksIGFlcyh3aWR0aCA9IHNjb3JlKSkgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG91ciA9IENPR19Qcm9jZXNzKSwgc2l6ZSA9IDUpICsKICBnZW9tX25vZGVfdGV4dChudWRnZV95ID0gMC4xLCBzaXplID0gMy4yLCBhZXMobGFiZWwgPSBlZ2dOT0dfbmFtZSwgY29sb3VyID0gQ09HX1Byb2Nlc3MpKSArCiAgc2NhbGVfZWRnZV93aWR0aChyYW5nZSA9IGMoMC4yLCAyKSkgKwogIHRoZW1lX2dyYXBoKGJhY2tncm91bmQgPSAid2hpdGUiLCBmb3JlZ3JvdW5kID0gZ3JleSgwLjUpLAogICAgcGxvdF9tYXJnaW4gPSBtYXJnaW4oMTAsIDEwLCAxMCwgMTApKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRkFMU0V9CiMgZXhwb3J0IGdlbmVzIHRoYXQgYXJlIGVzc2VudGlhbCBmb3IgZ3Jvd3RoIG9uIGZydWN0b3NlIChidXQgbm90IExCKQojIGRmX2ZpdG5lc3NfY29tcCAlPiUKIyAgIGZpbHRlcihjb250aW51b3VzIDw9IC0yICYgYHNob3J0IHB1bHNlYCA8PSAtMiAmIGBsb25nIHB1bHNlYCA8PSAtMikgJT4lCiMgICB3cml0ZV9jc3YoIi4uL2RhdGEvb3V0cHV0L2Vzc2VudGlhbGl0eV9mcnVjdG9zZS5jc3YiKQpgYGAK